2007-09-24
泛型学习
关键字: 泛型,java有限的泛型:
类型通配符:void printList(List l) {}
泛型类实例 java 代码
- public class Lhist
{ - private V[] array;
- private int size;
- public Lhist(int capacity) {
- array = (V[]) new Object[capacity];
- }
- public void add(V value) {
- if (size == array.length)
- throw new IndexOutOfBoundsException(Integer.toString(size));
- else if (value == null)
- throw new NullPointerException();
- array[size++] = value;
- }
- public void remove(V value) {
- int removalCount = 0;
- for (int i=0; i
- if (array[i].equals(value))
- ++removalCount;
- else if (removalCount > 0) {
- array[i-removalCount] = array[i];
- array[i] = null;
- }
- }
- size -= removalCount;
- }
- public int size() { return size; }
- public V get(int i) {
- if (i >= size)
- throw new IndexOutOfBoundsException(Integer.toString(i));
- return array[i];
- }
- }
评论
liudaoru
2007-09-24
extends 的新含意 第 6 页(共9 页)
在 Java 语言引入泛型之前,extends 关键字总是意味着创建一个新的继承自另一个类或接口的类或接口。
引入泛型之后,extends 关键字有了另一个含意。将 extends 用在类型参数的定义中(Collection<T extends Number>)或者通配符类型参数中(Collection<? extends Number>)。
当使用 extends 来指示类型参数限制时,不需要子类-父类关系,只需要子类型-父类型关系。还要记住,有限制类型不需要是该限制的严格子类型;也可以是 该限制。换句话说,对于 Collection<? extends Number>,您可以赋给它 Collection<Number>(尽管 Number 不是 Number 的严格子类型)和 Collection<Integer>、Collection<Long>、Collection<Float> 等等。
在任何这些含意中,extends 右边的类型都可以是参数化类型(Set<V> extends Collection<V>)。
在 Java 语言引入泛型之前,extends 关键字总是意味着创建一个新的继承自另一个类或接口的类或接口。
引入泛型之后,extends 关键字有了另一个含意。将 extends 用在类型参数的定义中(Collection<T extends Number>)或者通配符类型参数中(Collection<? extends Number>)。
当使用 extends 来指示类型参数限制时,不需要子类-父类关系,只需要子类型-父类型关系。还要记住,有限制类型不需要是该限制的严格子类型;也可以是 该限制。换句话说,对于 Collection<? extends Number>,您可以赋给它 Collection<Number>(尽管 Number 不是 Number 的严格子类型)和 Collection<Integer>、Collection<Long>、Collection<Float> 等等。
在任何这些含意中,extends 右边的类型都可以是参数化类型(Set<V> extends Collection<V>)。
liudaoru
2007-09-24
类型与类 第 3 页(共9 页)
泛型的引入使得 Java 语言中的类型系统更加复杂。以前,该语言具有两种类型 —— 引用类型和基本类型。对于引用类型,类型 和类 的概念基本上可以互换,术语子类型 和子类 也可以互换。
随着泛型的引入,类型和类之间的关系变得更加复杂。List<Integer> 和 List<Object> 是不同的类型,但是却是相同的类。尽管 Integer 扩展 Object,但是 List<Integer> 不是 List<Object>,并且不能赋给 List<Object> 或者强制转换成 List<Object>。
另一方面,现在有了一个新的古怪的类型叫做 List<?>,它是 List<Integer> 和 List<Object> 的父类。并且有一个更加古怪的 List<? extends Number>。类型层次的结构和形状也变得复杂得多。类型和类不再几乎是相同的东西了。
泛型的引入使得 Java 语言中的类型系统更加复杂。以前,该语言具有两种类型 —— 引用类型和基本类型。对于引用类型,类型 和类 的概念基本上可以互换,术语子类型 和子类 也可以互换。
随着泛型的引入,类型和类之间的关系变得更加复杂。List<Integer> 和 List<Object> 是不同的类型,但是却是相同的类。尽管 Integer 扩展 Object,但是 List<Integer> 不是 List<Object>,并且不能赋给 List<Object> 或者强制转换成 List<Object>。
另一方面,现在有了一个新的古怪的类型叫做 List<?>,它是 List<Integer> 和 List<Object> 的父类。并且有一个更加古怪的 List<? extends Number>。类型层次的结构和形状也变得复杂得多。类型和类不再几乎是相同的东西了。
liudaoru
2007-09-24
擦除 第 1 页(共9 页)
也许泛型最具挑战性的方面是擦除(erasure),这是 Java 语言中泛型实现的底层技术。擦除意味着编译器在生成类文件时基本上会抛开参数化类的大量类型信息。编译器用它的强制类型转换生成代码,就像程序员在泛型出现之前手工所做的一样。区别在于,编译器开始已经验证了大量如果没有泛型就不会验证的类型安全约束。
通过擦除实现泛型的含意是很重要的,并且初看也是混乱的。尽管不能将 List<Integer> 赋给 List<Number>,因为它们是不同的类型,但是 List<Integer> 和 List<Number> 类型的变量是相同的类!要明白这一点,请评价下面的代码:
new List<Number>().getClass() == new List<Integer>().getClass()
编译器只为 List 生成一个类。当生成了 List 的字节码时,将很少剩下其类型参数的的跟踪。
当生成泛型类的字节码时,编译器用类型参数的擦除 替换类型参数。对于无限制类型参数(<V>),它的擦除是 Object。对于上限类型参数(<K extends Comparable<K>>),它的擦除是其上限(在本例中是 Comparable)的擦除。对于具有多个限制的类型参数,使用其最左限制的擦除。
如果检查生成的字节码,您无法说出 List<Integer> 和 List<String> 的代码之间的区别。类型限制 T 在字节码中被 T 的上限所取代,该上限一般是 Object。
也许泛型最具挑战性的方面是擦除(erasure),这是 Java 语言中泛型实现的底层技术。擦除意味着编译器在生成类文件时基本上会抛开参数化类的大量类型信息。编译器用它的强制类型转换生成代码,就像程序员在泛型出现之前手工所做的一样。区别在于,编译器开始已经验证了大量如果没有泛型就不会验证的类型安全约束。
通过擦除实现泛型的含意是很重要的,并且初看也是混乱的。尽管不能将 List<Integer> 赋给 List<Number>,因为它们是不同的类型,但是 List<Integer> 和 List<Number> 类型的变量是相同的类!要明白这一点,请评价下面的代码:
new List<Number>().getClass() == new List<Integer>().getClass()
编译器只为 List 生成一个类。当生成了 List 的字节码时,将很少剩下其类型参数的的跟踪。
当生成泛型类的字节码时,编译器用类型参数的擦除 替换类型参数。对于无限制类型参数(<V>),它的擦除是 Object。对于上限类型参数(<K extends Comparable<K>>),它的擦除是其上限(在本例中是 Comparable)的擦除。对于具有多个限制的类型参数,使用其最左限制的擦除。
如果检查生成的字节码,您无法说出 List<Integer> 和 List<String> 的代码之间的区别。类型限制 T 在字节码中被 T 的上限所取代,该上限一般是 Object。
liudaoru
2007-09-24
擦除的含意 第 2 页(共9 页)
擦除有很多初看起来似乎奇怪的含意。例如,因为类只可以实现一个接口一次,所以不能像下面这样定义类:
// invalid definition
class DecimalString implements Comparable<String>, Comparable<Integer> { ... }
由于擦除,上面的声明没有意义。Comparable 的两个实例化是同一个接口,并且它们指定相同的 compareTo() 方法。不能实现一个方法或接口两次。
擦除的另一个更加烦人的含意是,不能使用类型参数实例化一个对象或数组。这意味着您不能在带有类型参数 T 的泛型类中使用 new T() 或 new T[10]。编译器只是不知道生成什么样的字节码。
该问题有几个应急方案,一般涉及反射和类常量(Foo.class)的使用,但是这二者是很麻烦的。Lhist 例子类中的构造函数显示了解决该问题的一种技术(参阅 实现构造函数),toArray() 的讨论(参阅 用 Class<T> 替换 T[])中提供了另一种技术。
擦除的另一个含意是,它使得使用 instanceof 来测试一个引用是不是参数化类型的一个实例是没有意义的。运行时只是不能区分 List<String> 和 List<Number>,所以测试 (x instanceof List<String>) 是没有任何意义的。
类似地,下面的方法不能提高程序的类型安全:
public <T> T naiveCast(T t, Object o) { return (T) o; }
编译器将只是发出一个 unchecked 警告,因为它不能确定强制类型转换是否安全。
擦除有很多初看起来似乎奇怪的含意。例如,因为类只可以实现一个接口一次,所以不能像下面这样定义类:
// invalid definition
class DecimalString implements Comparable<String>, Comparable<Integer> { ... }
由于擦除,上面的声明没有意义。Comparable 的两个实例化是同一个接口,并且它们指定相同的 compareTo() 方法。不能实现一个方法或接口两次。
擦除的另一个更加烦人的含意是,不能使用类型参数实例化一个对象或数组。这意味着您不能在带有类型参数 T 的泛型类中使用 new T() 或 new T[10]。编译器只是不知道生成什么样的字节码。
该问题有几个应急方案,一般涉及反射和类常量(Foo.class)的使用,但是这二者是很麻烦的。Lhist 例子类中的构造函数显示了解决该问题的一种技术(参阅 实现构造函数),toArray() 的讨论(参阅 用 Class<T> 替换 T[])中提供了另一种技术。
擦除的另一个含意是,它使得使用 instanceof 来测试一个引用是不是参数化类型的一个实例是没有意义的。运行时只是不能区分 List<String> 和 List<Number>,所以测试 (x instanceof List<String>) 是没有任何意义的。
类似地,下面的方法不能提高程序的类型安全:
public <T> T naiveCast(T t, Object o) { return (T) o; }
编译器将只是发出一个 unchecked 警告,因为它不能确定强制类型转换是否安全。
发表评论
- 浏览: 54426 次
- 来自: 北京

- 详细资料
搜索本博客
最近加入圈子
最新评论
-
绝对居中定位(计算滚动位 ...
document.body.clientHeight这个。但是好象IE的总是不对 ...
-- by xqstation -
绝对居中定位(计算滚动位 ...
哦。也不对。。。那是屏幕的。。。烦。破IE不支持fix
-- by xqstation -
绝对居中定位(计算滚动位 ...
document.body.offsetHeight改成window.scree ...
-- by xqstation -
Oracle SQLServer 的随机 ...
构造指定分为的整数: select 77 + floor(dbms_random ...
-- by liudaoru -
Oracle SQLServer 的随机 ...
1、如果dbms_output.put_line的内容不能显示,需要在命令行中先 ...
-- by liudaoru






评论排行榜