本文介绍Java中的泛型机制。
1. 泛型概述 JDK5.0之后推出了泛型机制。在概述泛型之前,先看一下下面的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public class GenericTest01 { public static void main (String[] args) { List myList = new ArrayList(); Animal a = new Animal(); Bird b = new Bird(); Cat c = new Cat(); myList.add(a); myList.add(b); myList.add(c); Iterator it = myList.iterator(); while (it.hasNext()){ Object obj = it.next(); if (obj instanceof Bird){ Bird tempBd = (Bird) obj; tempBd.flying(); }else if (obj instanceof Cat){ Cat tempCt = (Cat) obj; tempCt.eating(); }else if (obj instanceof Animal){ Animal tempAml = (Animal) obj; tempAml.move(); } } } } class Animal { public void move () { System.out.println("动物在移动" ); } } class Cat extends Animal { public void eating () { System.out.println("猫在吃鱼" ); } } class Bird extends Animal { public void flying () { System.out.println("鸟儿在飞翔" ); } }
和前面自定义链表一样,存储的是Object类型数据,返回值也是它,这保证了存储数据类型的多样性 ,但是这样也带来了缺点,当我们获取集合中的元素时,返回的数据类型是Object,这时候为了进一步调用内部方法需要类型转换,此时的类型转换具有一定的繁杂。那么如何让其变得简单呢?能不能指定其返回的数据类型呢?
如果指定其返回的数据类型 ,那么也要指定其存储的数据类型 ,这就是泛型 。泛型用来指定集合中存储的数据类型,集合后面只要有尖括号,就说明该类支持泛型。用了泛型之后,集合中元素的数据类型更加统一了。迭代器也可以指定泛型。使用泛型之后,迭代器每一次迭代返回的数据都是指定的类型,不再需要先强制转换再调用方法。
泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考的,运行阶段泛型没用。
泛型的优点是集合中存储的元素类型统一了。从集合中取出的元素类型是泛型指定的类型,不需要进行大量的向下转型。缺点是导致集合中存储的元素缺乏多样性。大多数情况下集合中元素的类型还是统一的,所以这种特性被大家认可。
2. 泛型代码实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class GenericTest01 { public static void main (String[] args) { List<Animal> myList = new ArrayList<Animal>(); Animal a = new Animal(); Bird b = new Bird(); Cat c = new Cat(); myList.add(a); myList.add(b); myList.add(c); Iterator<Animal> it = myList.iterator(); while (it.hasNext()){ Animal obj = it.next(); if (obj instanceof Bird){ Bird tempBd = (Bird) obj; tempBd.flying(); }else if (obj instanceof Cat){ Cat tempCt = (Cat) obj; tempCt.eating(); }else { obj.move(); } } } }
上述集合在创建的时候在尖括号中指明了存储的数据类型是Animal类型,此时如果向其添加其他类型数据会报错。迭代器在创建的时候指明了其返回的数据类型是Animal。此时取出的元素均为Animal类型。泛型只是在一定程度上减少了代码的复杂度。
2.1 类型自动推断 JDK8及之后引入了自动类型推断机制 (也被称为钻石表达式),上面的List<Animal> myList = new ArrayList<Animal>();
中ArrayList中尖括号的内容是可以省略的,即List<Animal> myList = new ArrayList<>();
,这里的类型会自动推断。
3. 自定义泛型 Java支持在类型定义的时候自定义泛型。
1 2 3 4 5 6 7 8 9 10 11 12 13 class 类名<T > { public T get () { 方法体; } public void doSome (T t) { 方法体; } public T methods (T t) { 方法体; } }
其中,尖括号中的标识符可以随便写,一般写E 或者T (E是element的首字母,T是type的首字母),指明这是任意一个类型,然后在需要这个类型的方法中,写上该类型即可。在真正采用泛型的时候,会自动将指定的类型把E或者T给替换掉。如果不采用泛型,默认E或者T是Object。
4. 补充 除了上述的用法,还有<? extends ?>等用法,后续用到再追加。
5. 备注 参考B站《动力节点》。