java 泛型的学习和理解
2016-03-18 18:23
423 查看
首先,我也是借鉴许多网上的资料来进行模仿和理解,便于以后的时候,主要的目的为了记录下,方便以后回看。
最近在看数据结构和算法分析java 版的时候,直接被习题给难住了,根本无从下手,所以决定重新认识和了解下泛型,查漏补缺。
同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
泛型的类型参数可以有多个。
泛型的参数类型可以使用extends语句,例如。习惯上称为“有界类型”
泛型的参数类型还可以是通配符类型。例如Class
一般使用<#T#>来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type)
如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等,
若是 ?,则是默认是允许Object及其下的子类,也就是java的所有对象了。
所以说,如果是字每A,B,C,D…定义的,就是泛型,这里T只是名字上的意义而已
T—type,E—-Element
K—-key, V—-value
如果是?定义的,就是普通的Object或者其子类
举例说明: #号是多余的
Set<#T#> 表示 集合里 是 T类的实例
List<#E#> 表示 集合里 是 E类的实例
List<#?#> 表示 集合里的对象类型不确定,未指定
List 同 List<#?#> 是一样的。
在解析的时候,需要进行类型的强制转换。
下面是使用泛型的例子:
使用泛型的时候,直接获取的是相应的类型。不许强制转换。
注意:基本类型无法作为 T 的实际参数传递的
先看下面这个简单的例子:
Object obj=new Integer();
System.out.println(obj.getClass());
obj是引用,引用的类型是Object,实例的类型是Integer
我们知道,引用是栈保存的一个类似地址的信息,本身没有任何含义,真正能保存信息的是new Integer()所划分的内存空间。
即是说,Integer这个信息是在实例里的
第二组关键词:继承,父类,子类
Integer继承自Object
obj.getClass()调用的是Integer的getClass方法,当然Integer是没有该方法,于是一直回溯到父类Object,找到Object的getClass方法,实现是本地native方法,我们不知道内部怎么构造,但是可以肯定,它是在根据引用地址找到实例位置,确定实例类型。
综合第一组可知,在这里,实例类型是Integer
第三才是泛型。
其实在第一部里面已经说明过了。
GenTDemo并没有维护T的信息。
维护T信息的是T ob;
GenTDemo<#Integer#> iObject执行这一部的时候,ob就认为自己是个Integer类型了。当它具有了实例之后,你才能调用getClass方法
所以综合上两点才表现出了你看到的效果。
对于GenTDemo来说,一旦运行,它就不在乎T是什么类型了,但是ob需要知道自己的类型吧?这个Integer被维护在了实例里。
4.2 泛型的限制,可以向上限制也可以向下限制
下面截图中都有解释说明
4.3 泛型的方法的使用
使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
需要注意,一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。
最近在看数据结构和算法分析java 版的时候,直接被习题给难住了,根本无从下手,所以决定重新认识和了解下泛型,查漏补缺。
1.什么是java 泛型
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。2.泛型的使用的限制
泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
泛型的类型参数可以有多个。
泛型的参数类型可以使用extends语句,例如。习惯上称为“有界类型”
泛型的参数类型还可以是通配符类型。例如Class
3.? E T 的含义后区别
遇到 T,E,K,V等,是用到了java中的泛型。一般使用<#T#>来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type)
如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等,
若是 ?,则是默认是允许Object及其下的子类,也就是java的所有对象了。
所以说,如果是字每A,B,C,D…定义的,就是泛型,这里T只是名字上的意义而已
T—type,E—-Element
K—-key, V—-value
如果是?定义的,就是普通的Object或者其子类
举例说明: #号是多余的
Set<#T#> 表示 集合里 是 T类的实例
List<#E#> 表示 集合里 是 E类的实例
List<#?#> 表示 集合里的对象类型不确定,未指定
List 同 List<#?#> 是一样的。
4.代码说明
4.1 这里是默认的使用Object 的例子@/** * 通用类型的一个例子 on 2016/3/18. */ public class GenNormalDemo { private Object object; public GenNormalDemo(Object o){ this.object = o; } public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public String showType(){ return "实际参数的类型是="+object.getClass().getName(); } }
在解析的时候,需要进行类型的强制转换。
下面是使用泛型的例子:
/** * 使用泛型定义的类型 on 2016/3/18. */ public class GenTDemo<T> { private T object; public GenTDemo(T ob){ this.object = ob; } public T getObject() { return object; } public void setObject(T object) { this.object = object; } public String showType(){ return "泛型定义的类的实际参数的类型是="+object.getClass().getName(); } }
使用泛型的时候,直接获取的是相应的类型。不许强制转换。
注意:基本类型无法作为 T 的实际参数传递的
下面是对为什么能获取到对应类型的解释,为什么类没有受到类擦除机制的影响。(摘录)
第一组关键词:引用,实例化。先看下面这个简单的例子:
Object obj=new Integer();
System.out.println(obj.getClass());
obj是引用,引用的类型是Object,实例的类型是Integer
我们知道,引用是栈保存的一个类似地址的信息,本身没有任何含义,真正能保存信息的是new Integer()所划分的内存空间。
即是说,Integer这个信息是在实例里的
第二组关键词:继承,父类,子类
Integer继承自Object
obj.getClass()调用的是Integer的getClass方法,当然Integer是没有该方法,于是一直回溯到父类Object,找到Object的getClass方法,实现是本地native方法,我们不知道内部怎么构造,但是可以肯定,它是在根据引用地址找到实例位置,确定实例类型。
综合第一组可知,在这里,实例类型是Integer
第三才是泛型。
其实在第一部里面已经说明过了。
GenTDemo并没有维护T的信息。
维护T信息的是T ob;
GenTDemo<#Integer#> iObject执行这一部的时候,ob就认为自己是个Integer类型了。当它具有了实例之后,你才能调用getClass方法
所以综合上两点才表现出了你看到的效果。
对于GenTDemo来说,一旦运行,它就不在乎T是什么类型了,但是ob需要知道自己的类型吧?这个Integer被维护在了实例里。
4.2 泛型的限制,可以向上限制也可以向下限制
/** * 泛型里面的 T extends 的含义包括了 原来的 继承和实现,是两者的结合 * T 必须是集合的类 * lh on 2016/3/18. */ public class CollectionGenFoo< T extends Collection> {
/** * lh on 2016/3/18. * 其中? 通配符泛型 表示不确定的类型 * 其中k 表示内部实现comparable 的类,类似String,int 等 */ public class Gen2Value<T,K extends Comparable<?>> { private T t; private K k; public Gen2Value(T t1,K k1){ this.t = t1; this.k = k1; }
/** * lh on 2016/3/18. * 其中? 通配符泛型 表示不确定的类型 * 其中k 表示内部实现comparable 的类,类似String,int 等,? super Double 而且必须是Double的父类 * */ public class GenSuper2Value<T,K extends Comparable<? super Double>> { private T t; private K k; public GenSuper2Value(T t1, K k1){ this.t = t1; this.k = k1; }
下面截图中都有解释说明
4.3 泛型的方法的使用
使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
需要注意,一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。
/** * lh on 2016/3/18. */ public class TMethoddemo { public <T> void f(T x){ Log.d("test","测试泛型方法 TMethoddemo x="+x.getClass().getName()); } }
最后
对于开头提出的问题,现在有点思路,还是希望有人帮助当然最好。。。。相关文章推荐
- rxjava转载
- 20145324 《Java程序设计》第3周学习总结
- Java常用的日期格式转换
- Java实现文件MD5加密
- jdk8多线程操作文件
- Spring 之九 整合Spring MVC
- Java基础之equals详解
- Java 生成二维码
- java判断字符串是否乱码
- 斐波那契堆(Fibonacci heap)原理详解(附java代码实现)
- java 请求url并解析
- Spring mvc @ResponseBody返回JSON前台JSP乱码解决
- 2. Add Two Numbers | Java最短代码实现
- java mybatis 之 mysqlmap 动态 sql 语句
- 怎样增强MyEclipse的代码自动提示功能
- SpringMVC那点事
- Java并发 线程池
- Spring MVC里面的预防 SQL 注入
- java读写excel文件
- SpringMVC定义Interceptor