泛型是在Java 1.5中被加入了,这里不讨论泛型的细节问题,这个在Thinking in Java第四版中讲的非常清楚,这里要讲的是super和extends关键字,以及在使用这两个关键字的时候为什么会不同的限制。
首先,我们定义两个类,A和B,并且假设B继承自A。下面的代码中,定义了几个静态泛型方法,这几个例子随便写的,并不是特别完善,我们主要考量编译失败的问题:
public class Generic{
//方法一
public static <T extends A> void get(List<T extends A> list)
{
list.get(0);
}
//方法二
public static <T extends A> void set(List<T extends A> list, A a)
{
list.add(a);
}
//方法三
public static <T super B> void get(List<T super B> list)
{
list.get(0);
}
//方法四
public static <T super B> void set(List<T super B> list, B b)
{
list.add(b);
}
}
编译之后,我们会发现,方法二和方法三没有办法通过编译。按照Thinking in Java上的说法,super表示下界,而extends表示上界,方法二之所以没有办法通过,是因为被放到List里面去的可能是A,也可能是任何A的子类,所以编译器没有办法确保类型安全。而方法三之所以编译失败,则是因为编译器不知道get出来的是B还是B的其他的什么子类,因为set方法四允许在list放入B,也允许在list中放入B的子类,也就没有办法保证类型安全。
上面的这段解释听起来可能有点奇怪,都是因为编译器无法判断要获取或者设置的是A和B本身还是A和B的其他的子类才导致的失败。那么Java为什么不干脆用一个关键字来搞定呢?
如果从下面的角度来解释,就能把这个为什么编译会出错的问题解释的更加的直白和清除,也让人更容易理解,先看下面的代码,还是A和B两个类,B继承自A:
public class Generic2{
public static void main(String[] args){
List<? extends A> list1 = new ArrayList<A>();
List<? extends A> list2 = new ArrayList<B>();
List<? super B> list3 = new ArrayList<B>();
List<? super B> list4 = new ArrayList<A>();
}
}
从上面这段创建List的代码我们就更加容易理解super和extends关键字的含义了。首先要说明的一点是,Java强制在创建对象的时候必须给类型参数制定具体的类型,不能使用通配符,也就是说new ArrayList<? extends A>(),new ArrayList<?>()这种形式的初始化语句是不允许的。
从上面main函数的第一行和第二行,我们可以理解extends的含义,在创建ArrayList的时候,我们可以指定A或者B作为具体的类型,也就是,如果<? extends X>,那么在创建实例的时候,我们就可以用X或者扩展自X的类为泛型参数来作为具体的类型,也可以理解为给?号指定具体类型,这就是extends的含义。
同样的,第三行和第四行就说明,如果<? super X>,那么在创建实例的时候,我们可以指定X或者X的任何的超类来作为泛型参数的具体类型。
当我们使用List<? extends X>这种形式的时候,调用List的add方法会导致编译失败,因为我们在创建具体实例的时候,可能是使用了X也可能使用了X的子类,而这个信息编译器是没有办法知道的,同时,对于ArrayList<T>来说,只能放一种类型的对象。这就是问题的本质。而对于get方法来说,由于我们是通过X或者X的子类来创建实例的,而用超类来引用子类在Java中试合法的,所以,通过get方法能够拿到一个X类型的引用,当然这个引用可以指向X也可以指向X的任何子类。
而当我们使用List<? super X>这种形式的时候,调用List的get方法会失败。因为我们在创建实例的时候,可能用了X也可能是X的某一个超类,那么当调用get的时候,编译器是无法准确知晓的。而调用add方法正好相反,由于我们使用X或者X的超类来创建的实例,那么向这个List中加入X或者X的子类肯定是没有问题的,因为超类的引用是可以指向子类的。
最后还有一点,这两个关键字的出现都是因为Java中的泛型没有协变特性的倒置的。
分享到:
相关推荐
泛型中extends和super的区别Java系列2021.pdf
主要介绍了Java泛型extends及super区别实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Java 泛型 super T 中 super 怎么 理解?与 extends 有何不同? - 副本
主要介绍了Java泛型extends关键字设置边界的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Java Generics and Collections 英文版,详细描述java 泛型技术
Java泛型编程指南.pdf 此文章译自SUN的泛型编程指南
super T>、Set<? extends T>的声明,是什么意思呢?<? super T>表示包括T在内的任何T的父类,<? extends T>表示包括T在内的任何T的子类,下面我们详细分析一下两种通配符具体的区别。 extends List&...
java 泛型接口示例 java 泛型接口示例 java 泛型接口示例
这是一个使用JAVA实现的泛型编程,分为两部分,第一部分创建泛型类,并实例化泛型对象,得出相加结果。 第二部分用户自行输入0--4,选择要进行的加减乘除运算或退出,再输入要进行运算的两个数,并返回运算结果及...
java 泛型方法使用示例 java 泛型方法使用示例 java 泛型方法使用示例
java 泛型类的类型识别示例 java 泛型类的类型识别示例 java 泛型类的类型识别示例
1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1....
java泛型技术之发展,学习JAVA 泛型的不错东东
深入理解java泛型,包括类名泛型的定义,方法泛型定义,泛型的返回
泛型编程 [翻译]Java泛型编程指南(上).htm
4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip...
本人搜集的资料,看了这三篇,泛型彻底理解了。
对java泛型以及反射机制进行原理和应用上的讲解,帮助初学者对这两个概念进行更轻松的掌握
主要介绍了Java泛型的用法及T.class的获取过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
java,学习java泛型,java培训之泛型.pptxjava培训之泛型.pptxjava培训之泛型.pptxjava培训之泛型.pptx