Java泛型的认识
希望弄懂:
一. 泛型的好处
二. 表述
三. <R extends T>的作用
四. <? super T>,<? extends T>作为参数类型的作用
五. wildcard嵌套 <? extends|super ? extends|super T>
一. JDK1.5 引入了泛型,好处:
1. 编译时,类型检查
2. 避免类型转换
例如,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
ArrayList list = new ArrayList(); list.add("str1") System.out.prinntln((String)list.get(0)).length());
缺陷:
1. 没有类型保证,如果list.add(new Object()); 那么(String)list.get(0); 就会ClassCastException
2. 没有使用list中的元素都要强制转换
在使用泛型,就方便多了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
ArrayList<String> list = new ArrayList<String>(); list.add("str1"); System.out.println(list.get(0).length());
对于JDK1.7或以上,还进一步简化:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
ArrayList<String> list = new ArrayList<>();
后面会自动添加类型;
二. 几种表述:
1. 泛型静态函数
public class C { public static <T> T foo(T v) { return null; } } //用法: String ret = C.foo("str");
2. 泛型类
public class C<T> { public T foo(T v) { return null; } } //用法: C<String> instance = new C<String>(); String ret = instance.foo("str");
3. 泛型成员函数
public class C { public <T> T foo(T v) { return null; } } //用法: C instance = new C(); String ret = instance.foo("str");
4. 泛型类的泛型成员函数
public class C<R> { public <T> T foo(T v1, R v2) { return null; } } //用法: C<String> instance = new C<String>(); Integer ret = instance.foo(1, "str");
5. 泛型类的泛型静态函数
public class C<R> { public static <T> T foo(T v1) { return null; } } // (R的泛型没意义) Integer ret = C.foo(1);
6. public class C<T> { public static T foo(T v) {return null;} } 不能编译
三. ,<R extends T>的作用
作为方法的类型,
extends提供R的上限,如<R extends Number>,R可以是Number,Integer,Double等继承Numberl类,起到限制作用。
没有<R super T>,如<R super Number>,R可以是Number, Serializable,由于子类都可以放到父类上,相当于Number,所以没意义的
如
public class C { public static <R extends Number> T foo(R v) { return v; } } Integer ret = C.foo(1);
作为类的类型,也是类似的
如
public class C<R extends Number> { public R foo(R v) { return v; } } C<Integer> instance = new C<Integer>(); Integer ret = instance.bar(1);
那么,采用<R extends Number>的好处有哪些呢:
1. v能知道是Number或子类,能提早使用Number的方法,v.intValue();
2. 现在具体化的范围,如C<String>编译错误
至于class C<R super Number> 同样不支持。
四. <? super T>,<? extends T>作为参数类型的作用
先说一下,泛型删除
<?>代表没类型,如果作为参数类型,就只能接收null值;如果作为返回类型,就只能返回Object;一般这类,只能用没有泛型的函数,或者说,不关心其类型
如
public class C<T> { public T foo(T v) { return v; } public String bar(int i) { return "" + i; } } C<?> instance = new C<?>(); Object ret = instance.foo(null); // 这个用法没实际作用 String sRet = instance.bar(1); // 主要调用没有类型部分
既然C<?>不用考虑T的类型,那么具体化也可以,如 C<?> instance = new C<String>();
这样设计,创建者能根据自己需要设置类型,而使用者就不用关系类型
如果需要使用数据类型,就可以使用
C<? super Number> 或 C<? extends Number>
C<? super Number> 适合传入类型,返回没类型,容器能向下兼容
如
C<? super Number> instance = new C<Object>(); Object ret = instance.foo(new Integer(0)); // 接受Number的参数;但返回值Object,一般用于,修改数据。
C<? extends Number> 适合返回类型,而且不能传入参数,容器能向上兼容
如
C<? extends Number> instance = new C<Integer>(); Number ret = instance.foo(null); // 不接收参数,但返回Number,一般用于,获取数据。
五. wildcard嵌套 <? extends|super ? extends|super T>
这部分其实没什么意义,可以看成<? super T>和<? extends T>,仅仅为了语言的完整性
以下用例子说明:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class C<T> { public C<? super T> foo(C<? super T> v) { return v; } public C<? extends T> bar(C<? extends T> v) { return v; } } C<? super Number> s = null; C<? extends Number> e = null; C<? super Number> sInstance = new C<Object>(); C<? super Number> ret1 = sInstance.foo(null); C<?> ret2 = sInstance.bar(e); C<? extends Number> eInstance = new C<Integer>(); C<?> ret3 = eInstance.foo(s); C<? extends Number> ret4 = eInstance.bar(null);
归纳如下:
<? super ? super T> 参数类型:null,返回值<? super T>
<? extends ? super T> 参数类型:<? extends T>,返回值<?>
<? super ? extends T> 参数类型<? super T>,返回值<?>
<? extends ? extends T> 参数类型为null, 返回值<? extends T>