java 泛型 数组元素不能是参数化类型_Java泛型

一、泛型概念

泛型是JavaSE1.5的新特效,泛型的本职是参数化类型,就是说所操作的数据类型被指定为一个参数,这种参数可以用在类、接口和方法中创建,分别称为泛型类、泛型接口、泛型方法。引用泛型的好处是安全简单。

泛型机制将类型转换时的类型检查从运行时提前到了编译时,使用泛型编写的代码比使用object时强制类型转换的机制具有更好的可读性和安全性。

二、为何引入泛型

JDK5以前,对象保存到集合中,取出需进行类型的强制转换,这样不可避免就会引发程序的一些安全性问题,例如:

ca26dde0ee2e9131d5b2dbbf22f2db76.png

出现上面错误是因为list默认的类型为Object类型,在之后的循环中,由于之前在list中也加入了Integer类型的值或其他编码原因。编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。

使用泛型

90f7450de2b9156d9b23a20a6975e727.png

编译器会在编译时报错,集合内只能存储java.lang.String类型的实例

三、泛型作用

泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。例如:

8bf28367b9dbdc981965fec9031fffe0.png

使用泛型时需要注意的问题:

1.参数化类型不考虑类型参数继承关系:

List list = new ArrayList();   //error

List list = new ArrayList();  //error

2.使用泛形时,泛形类型须为引用类型,不能是基本数据类型

3.在创建数组实例时,数组元素不能是参数化类型

四、泛型的通配符扩展应用

4.1通配符

问题:定义一个方法,接收一个任意集合,并打印出集合中的所有元素,如下所示:

a203b081e2dcb5d7239abf6d61f9f60a.png

l.由于print方法c参数的类型为Collection>是一种不确定的类型,因此在方法体内不能调用与类型相关的方法,例如add()方法。

2.总结:使用?通配符主要用于引用对象,使用了?通配符,就只能调对象与类型无关的方法,不能调用对象与类型有关的方法

4.2 限制的通配符

a. 限定通配符的上边界:(?必须是Number的子类)

9f978194995c26ffda927da53747db8f.png

b.限定通配符的下边界 : (?必须是Integer的父类)

8c6bb6c29ca315d48271963572601ec7.png

4.3 自定义泛型方法

泛型方法定义规则:

Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛形前,必须对泛形进行声明,语法:,T可以是任意字母,但通常必须要大写。通常需放在方法的返回值声明之前。

泛型方法定义:

public static T marshalle(T arg){}

泛型方法定义注意问题:

1.只有对象类型才能作为泛型方法的实际参数

2.在泛型中可以同时有多个类型

f346e7f206b32872968f8008cf2b54b7.png

五.自定义泛型类

如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型)

语法格式如下:

a747f7ecdd99914e43b0b89b5ed67d1d.png

加上限定符,就可以访问限定类型的方法,类型更明确

3df10c041a838dcefdb9a27c36cc7629.png

注:我们知道final类不可继承,在继承机制上class SomeString extends String是错误的,但泛型限定符使用时是可以的:,只是会给一个警告。

后面的通配符限定有一个super关键字,这里没有。

六、泛型擦除

泛型只在编译阶段有效,编译后类型被擦除了,也就是说jvm中没有泛型对象,只有普通对象。所以完全可以把代码编译为jdk1.0可以运行的字节码。

擦除的方式:

1.定义部分,即尖括号中间的部分直接擦除

public class GenericClass{}

擦除后:

public class GenericClass{}

2.引用部分如:

public T field1;

其中的T被替换成对应的限定类型,擦除后:

public Comparable field1;

3.如果没有限定类型:

public class GenericClass{

public T field1;

}

那么的替换为object,即:

public class GenericClass{

public Object field1;

}

4.有多个限定符的,替换为第一个限定类型名。如果引用了第二个限定符的类对象,编译器会在必要的时候进行强制类型转换

public class GenericClass{

public T field1;

}

类擦除后变为:

public class GenericClass{

public Comparable field1;

}

而表达式返回值返回时,泛型的编译器自动插入强制类型转换。

七、泛型的约束和限制

不能使用8个基本类型实例化类型参数

原因在于类型擦除,Object不能存储基本类型:byte,char,short,int,long,float,double,boolean

从包装类角度来看三个: Number(byte,short,int,long,float,double),char,boolean

类型检查不可使用泛型:

if(aaa instanceof Pair){}//error

Pair p = (Pair) a;//warn

Pairp;

Pairi;

i.getClass()==p.getClass();//true

不能创建泛型对象数组

GenericMethod[] o=null;//ok

o=new GenericMethod[10];//error

可以定义泛型类对象的数组变量,不能创建及初始化。

注,可以创建通配类型数组,然后进行强制类型转换。不过这是类型不安全的。

o=(GenericMethod[]) new GenericMethod>[10];

不可以创建的原因是:因为类型擦除的原因无法在为元素赋值时类型检查,因此jdk强制不允许。

有一个特例是方法的可变参数,虽然本质上是数组,却可以使用泛型。

安全的方法是使用List。

注:

1. 泛型类中,称为类型变量,实际上就相当于在类中隐形的定义了一个不可见的成员变量:`private T t;`,这是对象级别的,对于泛型类型变量来说是在对象初始化时才知道其具体类型的。而在静态域中,不需要对象初始化就可以调用,这是矛盾的。

2. 静态的泛型方法,是在方法层面定义的,就是说在调用方法时,T所指的具体类型已经明确了。

原文:http://www.cnblogs.com/steven520213/p/6747641.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值