- 为什么要有泛型
一般的类和方法,只能使用具体的类型,要么是基础类型,要么是自定义的类型。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。
例如,声明一个自定义类型,继承要求类型必须继承某父类,接口要求类型必须实现某一接口。所以,为了编写更加通用的代码,使代码能够应用于“某种不确定的类型”,JavaSE5后引入了泛型。
- 什么是泛型
泛型实现了参数化类型的概念,术语的意思是“适用于很多很多的类型”,把类型当做一个参数,在具体编程时指定,不指定默认Object。泛型在编程语言出现时,最后的目的是希望类或方法能够具备最广泛的表达能力。具体实现:解耦类或方法与所使用的类型关系的约束。
疑问:java并没有那么高的实现,与C++的泛型相比,存在很多弊端。
泛型最引人注目的引用就是集合类,泛型的主要目的之一就是用来指定容器要持有的类型的对象,而且有编译器来保证类型的正确性,可在编译期排错,保证运行期效率。
![](https://images2018.cnblogs.com/blog/1334786/201807/1334786-20180706185914272-2114524504.png)
![](https://images2018.cnblogs.com/blog/1334786/201807/1334786-20180706185928525-197654873.png)
参数类型与Object类:参数类型可在具体编码时,指定某一个具体类型。Object已经是一个具体类型了,需要强制转换为需要的类型
List<T> list = new ArrayList<T>(); List list = new ArrayList();//默认T为Object,使用Object,不利于编译期保证类型,后面取值也强转,可能会出错,降低运行期效率。 ...
元组:将一组对象打包成一个单一对象,这个容器允许读取其中的元素,不允许向其中存放新的对象。
public class TwoTuple<A,B>{//参数类型A、B可随意注入不同类型的对象 public final A a; public final B b; public TwoTuple(A a,B b){ this.a = a; this.b = b; } }
注:基本类型无法做参数类型,也就是必须使用Integer,Long等
- 泛型类与泛型方法
泛型方法所在类可以是泛型类也可以不是泛型类。无论何时,只要你能做到,你就应该尽量使用泛型方法。
public class GenericMethods{ public <T> void f(T x){ System.out.println(x.getClass().getName()); } public static void main(String[] s){ GenericMethods gm = new GenericMethods(); gm.f(1);//java.lang.Integer gm.f("1");//java.lang.String gm.f(1L);//java.lang.Long } }
对于一个static的方法而言,无法访问泛型类的类型参数,所以static方法需要使用泛型能力,就必须使其成为泛型方法
当使用泛型类时,必须创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不比指明参数类型类型,因为编译器会为我们找到具体的类型。这叫类型参数推断
运用泛型的类型参数推断可以,避免一些重复代码。
HashMap<? extends Object> map = New.map();
- 泛型的擦除
public class ErasedTypeEquivalence{ public static void main(String s[]){ Class class1 = new ArrayList<String>().getClass(); Class class2 = new ArrayList<Integer>().getClass(); System.out.println(class1 == class2);//true } }
ArrayList<String>与ArrayList<Integer>是同一种类型。在泛型代码内部,无法获取有关泛型参数类型的任何信息。
ArrayList<String>与ArrayList<Integer>被擦除成ArrayList,String及Integer被擦除成Object。
当你编写代码的时候,你时刻要提醒自己,你只是看起来好像拥有有关参数的类型信息而已,可以理解为编译器知道String类型,但是运行期虚拟机不知道,认为是Object。
public class Erased<T>{ private final int SIZE = 100; public static void main(String[] s){ if(s instanceof T){}//error T var = new T();//error T[] array = new T[SIZE];//error T[] araat = (T) new Object[SIZE];//unchecked warning } }
class Building{} class House extends Building{} public class ClassTypeCapture<T>{ Class<T> kind; public ClassTypeCapture(Class<T> kind){ this.kind = kind; } public boolean f(Object obj){ return kind.isInstance(obj); } public static void main(String s[]){ ClassTypeCapture ctc1 = new ClassTypeCapture<Building>(Building.class); System.out.println(ctc1.f(new Building())); System.out.println(ctc1.f(new House())); ClassTypeCapture ctc2 = new ClassTypeCapture<House>(House.class); System.out.println(ctc2.f(new Building())); System.out.println(ctc2.f(new House())); } }
泛型的通配符
public class Test{ public static void main(String[] s){ Fruit[] fruit = new Apple[10]; fruit[0] = new Apple(); fruit[1] = new Fushishan(); try{ fruit[0] = new Fruit(); }catch(Exception e){ System.out.println(e); } try{ fruit[0] = new Orange(); }catch(Exception e){ System.out.println(e); } } } class Fruit{} class Apple extends Fruit{} class Orange extends Fruit{} class Fushishan extends Apple{}