java高级特性之泛型

泛型擦除

反射机制

自定义泛型类

自定义类型方法

java泛类型相关知识

1 为什么使用泛型

解决元素存储时候的安全性问题,同时解决获取集合元素的时候类型强转的问题。

提高代码的重用率。

例如编写一个泛型类,而我们不去关心类的具体类型,而用T来代表其变化的类型。T不能代表基本数据类型。

泛型注意:

在使用泛型的表达式中,如果两边都使用了泛型,那么两边的泛型必须一致。

如果表达式只有一边使用了泛型,那么表达式的另一边可以不使用泛型。

(如果任何类型的数据都可以添加到集合中,造成集合类型不安全,另外读取出来的对象可能需要转换,使用繁琐,容易出现)

泛型中的几个概念:

以ArrayList为例,<>念做 typeof

ArrayList中的E,称为类型参数变量

ArrayList中的Integer被称为实际类型参数

整个ArrayLIst泛型类型

整个ArrayList称为参数化的类型ParameterizedType.

ClassCastException(类转换异常)

如下代码:

ArrayList a1 = new ArrayList();

a1.add(dog);

a1.add(cat);

Dog temp = a1.get(0);

System.out.println(a1.get(0));

Dog temp = (Dog) a1.get(0);

//dog是Dog类的一个实例

首先定义了一个ArrayList 类型的集合,然后往集合里面添加了Dog类型的对象以及Cat类型的对象,这里是完全允许的,因为所有的类型集合都默认为Object类,在javac阶段也没有问题,但是在java阶段(运行阶段)就会出现类型转换的异常,ClassCastException。

分析:

1.当我们将一个对象放入集合的时候,集合不会记住对象的类型,当再次从集合中取出对象的时候,该对象的编译类型为Object类型,而运行时类型任何为其本身的类型。

2.若想使用该对象,必须要做强制转换。

【摘自某博客】

【泛型,JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。】

【安全隐患的理解】:

在java1.5之前,没有泛型的情况下,通过对类型Object 的引用来实现参数的“任意化”,任意化带来的确定就是要做显示的强制类型转换,而且要求开发者必须对实际参数类型预知的情况下进行,而且对于强制类型转换错误的情况下,javac不会显示错误,在运行的时候才会异常,导致jvm崩溃。这是一个安全的隐患。

参考代码TestGenerics.java

泛型类

泛型类的声明:

class/interface name


//当通过对象调泛型方法时,指明泛型方法的类型。

public <E> List<E> fromArrayToList(E[] e,List<E> list){

for(E xx : e){

list.add(xx);

}

return list;

}

//

List<Integer> list3 = order.fromArrayToList(in, list2);

泛型与继承:

若类B是类A的子类,那么List < B >和 List< A >没有继承关系。

若想在泛型中使用继承,那么可以使用通配符?

List< B > 和List< A >都是List< ? >的子类

List< ? extends A>可以存放类A及其子类的

List< ? super A> 可以存放类A及其父类

使用通配符的集合:

List< ? > list :可以从使用通配符的集合list中获取数据,其元素类型为Object。不可以往通配符的集合中list添加数据除了null之外。

泛型擦除

我们发现,在使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型, 传入不同泛型实参的泛型类在内存上只有一个,即还是原来的最基本的类型(new 出来的对象是何种类型,那么它在内存上就是什么类型), 当然,在逻辑上我们可以理解成多个不同的泛型类型。

究其原因,在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。

对此总结成一句话:泛型类在逻辑上看以看成是多个不同的类型,实际上都是相同的类型。【泛型擦出】

java核心技术一书中的观点:
jvm中没有泛型类型的对象,所有的对象都是普通对象。无论何时定义了一个泛型类型,都自动的提供了一个相应的原始类型,(raw type),原始类型的名字就是删除了类型参数后的泛型类型名,擦除(erased)类型变量,并替代类限定类型。
翻译泛型表达式:
由于泛型擦除机制,编译器会将泛型方法翻译为2条虚拟机指定
1调用原始的方法
2对于返回的Object类型的数据强制类型转换为泛型类型。
总之需要记住有关java泛型转换的事实:
1,虚拟机中没有泛型,只有普通的类和方法
2,所有的类型参数都是由他们的限定类型替换
3,桥方法被合成用来保持多态
4,为保持类型的安全性,必要时插入强制类型转换。

反射和泛型

Class类是泛型的,String.class实际上是Class类的对象,也是唯一的对象。
类型参数十分有用,因为它允许Class方法的返回类型更加具有针对性。

JVM中的泛型类型信息
java泛型的卓越特性就是泛型擦除,被擦除的类型仍然可以通过反射API获取泛型信息。
如下方法:
public static < T extends Comparable < ? supper T>> T min(T[] a)

通过反射API可以获取:
在SE5.0之后,新的接口Type,这个接口下包含的子类型:
Class:描述具体类型
TypeVariable接口:描述类型变量(Textends Comparable < ? supper T>)
WildcardType接口:描述通配符(如?supper T)
ParameterizedType接口:描述泛型类或者接口类型(Comparable < ? supper T>)
GenericArrayType接口:描述泛型数组 T[] a

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值