您的位置:首页 > 编程语言 > Java开发

java 泛型的学习和理解

2016-03-18 18:23 423 查看
首先,我也是借鉴许多网上的资料来进行模仿和理解,便于以后的时候,主要的目的为了记录下,方便以后回看。

最近在看数据结构和算法分析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());
}

}




最后

对于开头提出的问题,现在有点思路,还是希望有人帮助当然最好。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: