Java 泛型
如果不使用泛型,把一个对象添加到集合中,会被存储为Object型;取出来也是Object型,往往需要强制类型转换。
泛型,即参数化类型(parameterized type)。
使用泛型后,集合中只能存储该类型的对象,存储为该类型,取出来也是该类型。
Java7之前:
1 //不能缺省后面的类型 2 HashSet<String> hashSet=new HashSet<String>(); 3 HashMap<String,String> hashMap=new HashMap<String, String>();
Java7的菱形语法:
1 //可以缺省后面的类型。<>像一个菱形,所以叫做菱形语法 2 HashSet<String> hashSet=new HashSet<>(); 3 HashMap<String,String> hashMap=new HashMap<>();
Java9增强了菱形语法,允许在定义接口、类、方法时使用参数化类型(泛型):
1 //泛型放在接口名、类名后面 2 interface MyInterface<T,V>{ 3 //声明一个抽象方法,形参为T、V类的对象 4 void test(T t,V v); 5 }
1 //使用匿名内部类实现接口,并创建实例 2 MyInterface<String,String> myInterface=new MyInterface<>(){ 3 @Override 4 public void test(String str1, String str) { //重写时要替换原来的泛型参数 5 //...... 6 } 7 };
1 class MyClass<T>{ 2 //声明一个成员变量 3 private T t; 4 //构造函数 5 public MyClass(T t){ 6 this.t=t; 7 } 8 //返回值为T类型 9 public T getT(){ 10 return this.t; 11 } 12 13 }
不能赋值/传值给抽象的泛型,只能赋值/传值给具体的泛型:
1 //这是不行的,使用时T要替换为具体的类型 2 MyClass<T> myClass=new MyClass<>("ok");
1 //ok 2 MyClass<String> myClass=new MyClass<>("ok");
定义接口、类、函数时,完全可以把泛型当成普通类型使用。使用这些接口、类、函数时,必须指定(泛型的)具体类型。
1 //要指定(泛型的)具体类型 2 class MyClass2 extends MyClass<String>{ 3 //..... 4 } 5 6 //也可以缺省,默认为Object型 7 class MyClass3 extends MyClass{ 8 //..... 9 }
并不存在泛型类,MyClass<String>、MyClass<int>都只是一个类(MyClass),只生成一个.class文件,但数据类型并不等价。
泛型可以使用类型通配符:
<?> 表示可以是任何类型,相当于Object
<? extends ClassA> 设置上限,表示此参数可以是ClassA的任何(直接、间接)子类
<? super ClassA> 设置下限,表示此参数可以是ClassA的任何(直接、间接)父类
可以把带泛型的对象赋给不带泛型(相当于泛型为Object)的对象,会发生类型擦除:
1 HashSet<String> strSet=new HashSet<>(); 2 //会忘记strSet的类型,objSet会保存为Object型 3 HashSet objSet=strSet;