1 直观印象
在JDK1.5之前的版本中,对于一个Collection类库中的容器类实例,可将任意类型
对象加入其中(都被当作Object实例看待);从容器中取出的对象也只是一个Object实例,需要将其强制转型为期待的类型,这种强制转型的运行时正确性由程序员自行保证。
例如以下代码片断:
List intList = new ArrayList(); //创建一个List,准备存放一些Integer实例
intList.add(new Integer(0));
intList.add(“1”); //不小心加入了一个字符串;但在编译和运行时都不报错,只有仔细的代码走 //才能揪出
Integer i0 = (Integer)intList.get(0);
Integer i1 = (Integer)intList.get(1); //编译通过,直到运行时才抛ClassCastException
|
而在JDK1.5中,可以创建一个明确只能存放某种特定类型对象的容器类实例,例如如下代码:
List<Integer> intList = new ArrayList<Integer>(); //intList为存放Integer实例的List
intList.add(new Integer(0));
Integer i0 = intList.get(0); //无需(Integer)强制转型;List<Integer>的get()返回的就是Integer类 //型对象
intList.add(“1”); //编译不通过,因为List<Integer>的add()方法只接受Integer类型的参数
|
“List<Integer> intList = new ArrayList<Integer>();”就是最简单且最常用的Generic应用;显然,运用Generic后的代码更具可读性和健壮性。
2 Generic类
JDK1.5中Collection类库的大部分类都被改进为Generic类。以下是从JDK1.5源码中
截取的关于List和Iterator接口定义的代码片断:
public interface List<E> {
void add(E x);
Iterator<E> iterator;
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
|
以List为例,“public interface List<E>”中的E是List的类型参数,用户在使用List
时可为类型参数指定一个确定类型值(如List<Integer>)。类型值为Java编译器所用,确保用户代码类型安全。例如,编译器知道List<Integer>的add()方法只接受Integer类型的参数,因此如果你在代码中将一个字符串传入add()将导致编译错误;编译器知道Iterator<Integer>的next()方法返回一个Integer的实例,你在代码中也就无需对返回结果进行(Integer)强制转型。代码检验通过(语法正确且不会导致运行时类型安全问题)后,编译器对现有代码有一个转换工作。简单的说,就是去除代码中的类型值信息,在必要处添加转型代码。例如如下代码:
public String demo() {
List<String> strList = new ArrayList<String>();
strList.add(“Hello!”);
return strList.get(0);
}
|
编译器在检验通过后,将其转换为:
public String demo() {
List strList = new ArrayList(); //去除类型值<String>
strList.add(“Hello!”);
return (String)strList.get(0); //添加转型动作代码(String)
}
|
可见,类型值信息只为Java编译器在编译时所用,确保代码无类型安全问题;验证通过之后,即被去除。对于JVM而言,只有如JDK1.5之前版本一样的List,并无List<Integer>和List<String>之分。这也就是Java Generics实现中关键技术Erasure的基本思想。以下代码在控制台输出的就是“true”。
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
System.out.println(strList.getClass() == intList.getClass());
|
可以将Generic理解为:为提高Java代码类型安全性(在编译时确保,而非等到运行时才暴露),Java代码与Java编译器之间新增的一种约定规范。Java编译器在编译结果*.class文件中供JVM读取的部分里没有保留Generic的任何信息;JVM看不到Generic的存在。
对于Generic类(设为GenericClass)的类型参数(设为T):
1) 由于对于JVM而言,只有一个GenericClass类,所以GenericClass类的静态字段和静态方法的定义中不能使用T。T只能出现在GenericClass的非静态字段或非静态方法中。也即T是与GenericClass的实例相关的信息;
2) T只在编译时被编译器理解,因此也就不能与运行时被JVM理解并执行其代表的操作的操作符(如instanceof 和new)联用。
class GenericClass<T> {
T t1;
public void method1(T t){
t1 = new T(); //编译错误,T不能与new联用
if (t1 instanceof T) {}; //编译错误,T不能与instanceof联用
};
static T t2; //编译错误,静态字段不能使用T
public static void method2(T t){};//编译错误,静态方法不能使用T
}
|
Generic类可以有多个类型参数,且类型参数命名一般为大写单字符。例如Collection类库中的Map声明为:
public interface Map<K,V> {
……;
}
|
3 Generic类和原(Raw)类
对每一个Generic类,用户在使用时可以不指定类型参数。例如,对于List<E>,用户
可以以“List<String> list;”方式使用,也可以以“List list;”方式使用。“List<String>”被称为参数化的Generic类(类型参数被赋值),而“List”称为原类。原类List的使用方式和效果与JDK1.5之前版本List的一样;使用原类也就失去了Generic带来的可读性和健壮性的增强。
允许原类使用方式的存在显然是为了代码的向前兼容:即JDK1.5之前的代码在JDK1.5下仍然编译通过且正常运行。
当你在JDK1.5中使用原类并向原类实例中添加对象时,编译器会产生警告,因为它无法保证待添加对象类型的正确性。编译通过是为了保证代码向前兼容,产生警告是提醒潜在的风险。
public void test () {
List list = new ArrayList();
list.add("tt");//JDK1.5编译器对此行产生警告
}
|
4 Generic类和子类
List<String> ls = new ArrayList<String>();
List<Object> lo = ls; //编译错误:Type mismatch: cannot convert from List<Dummy> to //List<Object>
|
以上第二行代码导致的编译错误“Type mismatch: cannot convert from List<Dummy> to
List<Object>”是不是有点出人意料?直观上看,就像String是Object的子类,因此‘Object o = “String”’合法一样,存放String的List是存放Object的List的子类,因此第二行应该是合法的。反过来分析,如果第二行是合法的,那么如下会导致运行时异常的代码也是合法的:
lo.add(new Object); //会导致在ls中添加了非String对象
String s = ls.get(0); //ls.get(0)返回的实际上只是一个Object实例,会导致ClassCastException
|
编译器显然不允许此种情形发生,因此不允许“List<Object> lo = ls”编译通过。
因此,直观上的“存放String的List是存放Object的List的子类”是错误的。更一般的说,设Foo是Bar的子类,G是Generic类型声明,G<Foo>不是G<Bar><span
分享到:
相关推荐
1. **泛型(Generics)**:泛型是JDK1.5引入的最大变革之一。它允许在类、接口和方法中使用类型参数,提高了代码的类型安全性和重用性。泛型帮助程序员在编译时检查类型错误,避免了运行时的强制类型转换,使代码...
JDK1.5,也称为Java 5.0,是一个重要的版本,它引入了许多新的特性和改进,对Java语言的发展产生了深远影响。 一、泛型(Generics) 在Java 5.0中,最重要的特性之一就是泛型的引入。泛型允许开发者在定义类、接口...
综上所述,JDK1.5是Java发展历程中的一个重要里程碑,它的特性改进了编程体验,提升了代码质量和运行效率。而64位Windows版的JDK1.5,则是针对Windows用户的一种优化选择,满足了开发者在64位环境下的需求。文件"jdk...
- 泛型是JDK 1.5中最显著的新特性之一,它允许程序员在类型级别进行编程,从而提高代码的可读性和重用性,同时减少了强制类型转换的错误。 - 使用泛型可以避免运行时类型检查异常,并且使得集合操作更加安全。 2....
Java 5.0(也称为 JDK 1.5)引入了一系列重要的新特性,这些特性极大地提高了开发者的编程效率和代码质量。其中最显著的特性之一便是泛型(Generics)。本文将详细介绍泛型的概念、使用方式以及它如何帮助开发者编写...
在 JDK 1.5 中,Java 语言引入了一系列重要的新特性,极大地提升了代码的可读性、安全性以及效率。以下是对这些新特性的详细解析: 1. 泛型(Generics) 泛型是 JDK 1.5 最重要的改进之一,它允许在定义集合类时...
【JDK 1.5新特性详解】 JDK 1.5是Java发展历程中的一个重要里程碑,引入了许多创新特性,极大地提升了开发效率和代码质量...JDK 1.5的这些更新奠定了后续版本许多新特性的基础,对于理解和使用现代Java编程至关重要。
JDK 1.5 是Java发展历程中的一个重要里程碑,它引入了一系列新特性,极大地提升了编程的效率和代码的可读性。以下将详细讲解其中的一些关键特性及其应用。 1. 类型安全的枚举(Type-Safe Enumerations) 在JDK 1.5...
这个压缩包包含了三个不同版本的JDK:JDK 1.5、JDK 1.6和JDK 1.8,其中1.5和1.6是早期版本,而1.8是最流行且广泛使用的版本之一。 **JDK 1.5(也称为Java 5.0)** JDK 1.5在2004年发布,引入了许多重要的新特性,如...
** JDK 1.5,也称为Java SE 5.0,是Java开发工具包的一个重要版本,它引入了许多显著的新特性和改进,极大地提升了Java语言的效率和可维护性。以下是一些主要的新特性及其详细解释:** 1. **泛型(Generics)** ...
泛型是JDK1.5最重要的特性之一,它允许在类、接口和方法声明中使用类型参数,以实现数据类型的参数化。泛型提高了代码的类型安全性和可读性,减少了类型转换的需要,并允许编译器检查类型错误。 2. **自动装箱与...
在压缩包"IBMJDK1.5linux.zip"中,主要包含的是IBM JDK 1.5的安装文件和相关文档。安装完成后,开发者可以通过设置环境变量(如JAVA_HOME、PATH)来使用这个JDK。通常,这个JDK会包含Java编译器(javac)、Java解释...
JDK1.5(Java Development Kit 1.5)的发布标志着Java进入了一个新的阶段,其中最显著的变化之一便是引入了泛型(Generics)。本文将深入探讨JDK1.5中的泛型这一新特性。 #### 二、泛型的基本概念 **泛型**是一种...
JDK1.5是Oracle公司于2004年发布的一个重要版本,代号为"Tioga",它在Java的历史上具有里程碑式的意义,引入了许多重要的新特性和改进。 ### 1. 泛型(Generics) JDK1.5最重要的特性之一就是泛型的引入。泛型允许...
泛型是JDK 1.5中最显著的新特性之一,它允许在类、接口和方法中定义类型参数,增强了类型安全,减少了强制类型转换,同时提高了代码的可读性和复用性。例如,ArrayList<E> 表示一个可以存储任意类型E的列表。 2. *...
总的来说,JDK 1.5是一个里程碑式的版本,它的许多新特性如泛型、枚举、注解和自动装箱/拆箱等,极大地提高了Java开发的效率和代码质量,也为后续版本奠定了坚实的基础。如果你习惯了使用JDK 1.7,但对JDK 1.5有特殊...
综上所述,Java JDK1.5虽然已经是一个较为老旧的版本,但它带来的许多创新特性对于Java语言的发展有着深远的影响。即使在今天,理解并掌握这些特性仍然是每个Java开发者的基础技能。在实际项目中,如果需要兼容较旧...
JDK1.5引入了一些重要的新特性,如: 1. **Generics(泛型)**:允许在类、接口和方法中使用类型参数,增强了类型安全性和代码重用性。 2. **Autoboxing and Unboxing(自动装箱与拆箱)**:自动将基本类型与对应的...
1. **泛型(Generics)**:泛型是JDK1.5引入的一项重要特性,它允许在类、接口和方法中使用类型参数,从而提高了代码的类型安全性和重用性。泛型减少了强制类型转换,并帮助检测出潜在的类型错误。 2. **自动装箱与...
1. Generics(泛型):JDK 1.5最重要的特性之一就是引入了泛型,它允许开发者在类、接口和方法中定义类型参数,提高了代码的类型安全性,减少了类型转换的需要。例如,ArrayList取代了原来的ArrayList,T代表任意...