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

The Java Programming Language4th读书笔记-第十一章 泛型类型

2015-12-29 12:32 323 查看
当我们定义泛型类时,所有对这个泛型类的调用都是这个类的表达式。将变量strCell声明为Cell<String>就是在告诉编译器strCell将引用一个Cell<E>类型的对象,其中E是String类型的,而不是告诉编译器创建一个新的Cell<String>类。Cell<String>和Cell<Number>并不是两个分离的类,它们两个都是同一个类Cell的泛型类型调用,只不过以两种不同的方式应用到了两个不同的对象上。类Cell被称为对应于泛型类声明Cell<E>的原始类型(raw type);

泛型不管基于参数类型泛化出多少个对象,它们都属于同一个类;

泛型的类型参数不能和静态的参数扯上任何关系;

有两个地方只能使用类名而不能使用类型参数——那就是创建对象和数组;我们不能实例化E或是创建一个E的数组,这与我们不能拥有类型为E 的静态字段有着相同的原因:单一的类只有单一的toArray定义,编译器必须在编译期确定将要生成哪些用于创建对象或数组的代码;

编译器会对类型参数做些什么呢?编译器会使用最泛化的的可用类型来表示类型参数(经常是Object),并使用类型强制转换来确保类型的正确性;我们可以将泛型看作是一种(潜在地经过优化的)编写所有那些强制转型的快捷方式;

List<Integer>不是List<Number>的子类型,这与数组相反,在数组中Integer[]是Number[]的子类型;

有界通配符与有界类型不一样,它只可以拥有一个单一的边界,要么是上界,要么是下界;

通配符是有效使用泛型类型的精华所在,无论何时,只要方法接受的参数是参数化类型的,或者方法返回的是参数化类型,该参数化类型就几乎总是应该用某种通配符形式来表示;

泛型方法和泛型构造器通常用于以下两种情况:

需要引入类型变量来限制不同参数的参数化类型;

像toArray那样限制参数与返回类型;

如果我们的确想要创建参数化的方法调用,那么请记住我们不能参数化仅使用了简单方法名的调用,我们必须恰当地限定方法名,例如对实例方法使用this或super关键字,或是对静态方法使用类名;

我们需要理解擦除的过程,因为它会在两类关键的地方影响我们的程序:

涉及泛型类型的运行时动作;

方法的重载和覆盖;

从程序员的角度来看,尝试着使用合适的参数化类型集合会比使用数组更好,例如使用List<List<T>>代替List<T>[];

当我们编写代码时,最好坚持使用泛型表达式这一概念,而不要使用遗留的原始类型;

当方法签名涉及类型变量时,”相同的签名“这一定义对于两个泛型方法来说,要求它们拥有相同数量的类型变量,并且相应的类型变量具有相同的边界;

当子类型中的方法与超类型中可以访问到的方法拥有相同的名字并拥有覆盖等价的签名时,子类的方法就可能潜在地覆盖了超类中的这个方法。之所以说是”潜在地覆盖了“是因为有一个额外的条件必须满足:子类方法的签名必须与超类方法的签名相同,或者必须与超类方法签名的擦除相同;这一约束使得覆盖成了”单行道“:非泛型类型方法可以覆盖泛型类型方法,但反之却不可以,之所以允许我们这么做,是为了让我们可以在泛化一个现有类的同时,不会破坏先前覆盖了这个类的方法的现有子类;

当考虑到重载和覆盖时,我们要记住一条简单的规则:一定要考虑到方法签名的擦除,并记住我们不能对继承而来的方法进行泛化;

即使重载没有涉及泛型,也应尽量审慎地使用,用它只是为了提高程序清晰度。当泛型参合进来之后,更容易使得所创建的程序的意图只有通过详尽的查阅语言规范才能确立。要尽量避免在同一方法上混合使用泛型重载和非泛型重载,除非有非常具有说服力的理由;

泛型类型是一个很强大的工具,可以使我们更有效地编写程序,但是它是一件较难掌握的工具,并且很容易被误用。完全掌握泛型类型需要对类型理论有很好的了解,特别是协变(covariant)和逆变(contravariant)的类型特征;

几乎所有的人都可以在逆境中屹立不倒,但是如果想真正测试一个人的品格,赋予他全力吧!

                             ——亚伯拉罕·林肯
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 读书笔记