<? extends SomeClass>与<T extends SomeClass>的区别
2016-02-27 16:30
585 查看
看apache parquet源码时,发现代码各种泛型嵌套,有必要系统整理一下关于泛型的各种知识,在此做一总结。
首先是名词对应表,不需要记住右边的名字,但需要知道左边的各种用法
下面自己的实验包括代码,标号1是解决题目里描述的问题,其余的标号也是自己遇到的一些关键的问题。
1:
答:当我第一次接触这两名词时,感觉他们的功能是一样的,T可以代表任意的子类,?也可以代表任意的子类。
首先我们明确一下两边的名字,限制类型 & 通配符类型,
举个
注释里已经写清楚了,我们只能用T类型来进行一些操作,我们不能把T替换成?,因为?并不是一个类名,它只是一个通配符,然后举个
比如我们有一个Stack类,类里提供一个pullAll方法,我们想把一系列元素全部放到堆栈中,如下方法
这个方法编译时没问题,Iterable src的元素类型与堆栈的类型完全匹配就没有问题。但是假如有一个
因为在Java中,参数化类型是不可变的。所以现在我们的通配符类型就派上用场了,代码如下
此处就必须用通配符?,代表泛型的泛指“E的某个子类型的Iterator接口”。
扩张阅读:Stackoverflow : 区别
2、
不同于数组Object[] o,Long[] o,因为
参考这篇文章Java中的泛型方法的解释,注意区分Class与实例。
首先是名词对应表,不需要记住右边的名字,但需要知道左边的各种用法
List<String>—- 参数化的类型
List<E>—- 泛型
List<?>—- 无限制通配符类型
<E extends SomeClass>—- 有限制类型参数
List <? extends SomeClass>—- 有限制通配符类型
<T extends Comparable<T>>—– 递归类型限制
static <E> List<E> asList(E[] a)—- 泛型方法
下面自己的实验包括代码,标号1是解决题目里描述的问题,其余的标号也是自己遇到的一些关键的问题。
疑问&要解释的东西
1:<E extends ClassA>
与 <? extends ClassA>
有什么区别?
答:当我第一次接触这两名词时,感觉他们的功能是一样的,T可以代表任意的子类,?也可以代表任意的子类。首先我们明确一下两边的名字,限制类型 & 通配符类型,
<E extends ClassA>表示后续都只能使用E进行某些判断或操作,而
<? extends ClassA>?表示后续使用时可以是任意的。
举个
<E extends ClassA>最常见的例子,用于比较操作,比如返回“最大值”,“最大值”的定义为:整型、浮点型返回最大值,字符串返回字典序最大者,由于想调用
compareTo函数,我们让所有参数都继承
Compareble,即
T extends Comparable<T>,整个测试代码如下
package test; /** * 定义了 <T extends someClass>, * 里面的代码便只能用somClass的子类T进行比较或其他操作。 */ public class MaximumTest { // determines the largest of three Comparable objects public static <T extends Comparable<T>> T maximum(T x, T y, T z) { T max = x; // assume x is initially the largest if ( y.compareTo( max ) > 0 ) { max = y; // y is the largest so far } if ( z.compareTo( max ) > 0 ) { max = z; // z is the largest now } return max; // returns the largest object } public static void main(String args[]) { System.out.printf( "Max of %d, %d and %d is %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "Maxm of %.1f,%.1f and %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) ); System.out.printf( "Max of %s, %s and %s is %s\n","pear", "apple", "orange", maximum( "pear", "apple", "orange" ) ); } }
注释里已经写清楚了,我们只能用T类型来进行一些操作,我们不能把T替换成?,因为?并不是一个类名,它只是一个通配符,然后举个
<? extends ClassA>的例子。
比如我们有一个Stack类,类里提供一个pullAll方法,我们想把一系列元素全部放到堆栈中,如下方法
// Stack定义 public class Stack<E> { public Stack(); public E pop(); public boolean isEmpty(); } // ... public <E> void pushAll(Iterable<E> src) { for(E e : src) { push(e); } }
这个方法编译时没问题,Iterable src的元素类型与堆栈的类型完全匹配就没有问题。但是假如有一个
Stack<Number>调用了push(intVal),这里的intVal是Integer类型,这是可以的,因为Integer是Number的一个子类型,但下面的代码会报编译错误,
Stack<Number> numberStack = new Stack<Number>(); Iterable<Integer> integers = "..."; numberStack.pushAll(integers);
因为在Java中,参数化类型是不可变的。所以现在我们的通配符类型就派上用场了,代码如下
public void pushAll(Iterable<? extends E> scr) { for( E e : src) { push(e); } }
此处就必须用通配符?,代表泛型的泛指“E的某个子类型的Iterator接口”。
扩张阅读:Stackoverflow : 区别
2、List<Object> o = new ArrayList<Long>();
报错
不同于数组Object[] o,Long[] o,因为List<Type1>与
List<Type2>不互为子类型or超类型
3、无法创建泛型数组。
自己以前发的一片文章里由Cannot create a generic array of ArrayList引出的学习–Java范型就有这个,当时解释的有点瑕疵,<<Effective Java>> 第二版106页举了一个例子来说明这样的不安全性。
4、泛型方法的使用
static <E> List<E> asList(E[] a)—- 泛型方法
参考这篇文章Java中的泛型方法的解释,注意区分Class与实例。
相关文章推荐
- 从源码安装Mysql/Percona 5.5
- jackson、Gson反序列化 泛型
- Apache Isis 1.4.0 发布,领域驱动开发框架
- Linux快速构建apache web服务器
- Awstats处理多apache日志
- 安装perl模块小窍门
- JAVA泛型—— 3fe8 转
- JAVA泛型详解——转
- PHP+Apache在Windows 9x下的安装和配置
- Apache服务器配置全攻略
- Apache Web让JSP“动”起来
- Linux Apache+MySQL+PHP
- 建立Apache+PHP+MySQL数据库驱动的动态网站
- 浅析Ruby的源代码布局及其编程风格
- 编写高质量代码改善C#程序――使用泛型集合代替非泛型集合(建议20)
- apache 环境下 php 的配置注意事项
- 简单学习C#中的泛型方法使用
- C#通过反射创建自定义泛型
- C#泛型用法实例分析
- C语言泛型编程实例教程