1. 泛型实现了参数化类型的概念,意思是适用于许多许多的类型。在创建参数化类型的一个实例时,编译器会负责转型操作,并保证类型的正确性。
2. 泛型的主要目的之一是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。
3. 泛型类的格式:类名后面跟尖括号,尖括号里放入类型参数。
4. 元组用来将一组对象直接打包存储于某一个单一对象中。这个容器对象运行读取其中元素,但不允许向其中存放新的对象(用final保证)。元组可以具有任意长度,而且里面的对象可以是任意不同的类型。元组隐含地保持了其中元素的次序。
5. 内部类可以方位其外部类的类型参数。
6. 泛型可以用于接口,但基本类型无法作为类型参数。ForEach语法主要通过Iterator<>类中的next和hasNext函数来工作。
7. 类中可以包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。无论何时,应该尽可能使用泛型方法。对于static方法来说,无法访问泛型类的类型参数,只可能是泛型方法。
8. 要定义泛型方法,只需把泛型参数列表置于返回值之前。当使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不需要指定参数类型。因为编译器会为我们找到具体的类型,称为类型参数推断。
9. 当调用无参数的泛型方法时,只要等式左边的对象引用声明了类型参数,则通过类型参数推断可以避免等式右边重复的泛型参数列表。类型推断只对赋值操作有效,其他时候(指的是作为返回值直接传递给另外一个函数,此时的返回值为Object类型)并不起作用。
10. 在泛型方法中,可以显示指明类型,在(类名或this)加上点操作符与方法名之间插入尖括号,把类型置于尖括号内。
11. 泛型方法与可变参数列表可以共存。
12. 泛型可以应用于内部类以及匿名内部类。
13. 泛型的一个重要好处是能够简单而安全地创建复杂的模型。
14. 在泛型代码内部,无法获得任何有关泛型参数类型的信息。Java泛型是使用擦除来实现的,这意味着当使用泛型时,任何具体的类型信息都被擦除了,唯一知道的是你在使用一个对象。因此,List和List在运行时是相同的类型,都被擦除成它们的原生类型List。
15. 边界
16. 泛型类型参数将擦除到它的第一个边界,它可能有多个边界。.T擦除到A,就好像在类的声明中用A替换T一样。
17. 擦除是泛型实现的一种折中。泛型类型只有在静态类型检查期间才出现,在此之后,程序中所有泛型类型都被擦除,替换为它们的非泛型上界,若未指定,则被擦除成Object。擦除的核心动机是它使得泛化的客户端可以使用非泛化的类库。这称为迁移兼容性。
18. 擦除主要正当理由是从非泛化代码到泛化代码的转变过程,以及在不破坏现有类库的情况下,将泛型融入Java语言中。泛型不能用于显示地引用运行时类型的操作中,因为所有关于参数的类型信息都丢失。使用泛型不是强制的。
19. 在泛型中创建数组,使用Array.newInstance()是推荐的方式。
20. 因为擦除在方法体中移除了类型信息,所以在运行时的问题就是边界:即对象进入和离开方法的地点,这些正是编译器在编译期执行类型检查并插入转型代码的地点。
21. 泛型中的所有动作都发生在边界处,对传递进来的值进行额外的编译期检查,并插入对传递出去的值的转型。有助于澄清对擦除的泛型。
22. 通过引入类型标签来对擦除进行补偿。这意味着需要显示传递类型的class对象,以便可以在类型表达式中使用它。编译器将确保类型标签匹配泛型参数。
23. 成功创建泛型数组的唯一方式就是创建一个被擦除类型的新数组,然后对其转型。
24. 没有任何方式可以推翻底层的数组类型。只有通过改变擦除类型的边界,才能在初始化泛型类型参数时,相应改变数组的类型。
25. 边界使得可以在用于泛型的参数类型上设置限制条件,但更重要的效果是可以按照边界类型来调用方法。通配符?被限制为单一边界。
26. List Extends Fruit>flist = new ArrayList
27. 编译器将直接拒绝对参数列表中涉及通配符的方法的调用。编译器只关注传递进来和要返回的对象类型。
28. 超类型通配符 super class>,声明通配符是由某个特定类的任何基类来界定的。这样向容器添加子类或者class类是安全的。这里get的安全类型只能是Object。
29. 无界通配符>可以被认为是一种修饰,好像等价使用了原生类型。可以用在处理多个泛型参数的情形。
30. List实际上是List
31. 原生Holder将持有任何类型的组号,而Holder>将持有某种具体类型的同构集合,不能只是向其中传入Object。向接受确切泛型类型(没有通配符)的方法传递一个原生引用,会得到一个警告,因为确切的参数期望得到在原生类型中并不存在的信息。
32. 捕获转换需要使用>而不是原生类型。因为未指定的通配符类型被捕获,并转换成确切类型。捕获转换只有在方法内部,需要使用确切类型才使用。
33. 任何基本类型都不能作为类型参数,自动包装机制不能应用与数组。
34. 一个类不能实现同一个泛型接口的两种变体。因为擦除的原因,这两个变体会成为相同的接口。但是如果把两种变体去掉泛型参数,则可以。
35. 使用带有泛型类型参数的转型或instanceof不会有任何效果。新的转型转型形式,通过泛型类来转型。语法:类名.class.cast(对象)。
36. 由于擦除的原因,重载方法将产生相同的类型签名。
37. 基类劫持了接口,如:class Cat extendsComparablePet implements Comparable
38. 自限定类型:class A
class B extends C,Java中的泛型关乎参数和返回类型,因此能够产生使用导出类作为其参数和返回类型的基类,还能将导出类型用于域类型。这意味着基类用导出类替代其参数,泛型基类编程一种其所有导出类的公共功能的模板。在所产生的类中将使用确切类型而不是基类型。
39. 对于class A
40. 协变参数类型:方法参数类型和返回类型会随子类而变化。导出类的方法应该能够返回比它覆盖的基类方法更具体的类型。自限定泛型事实上将产生确切的导出类型作为其返回值。在非泛型代码中,参数类型不能随子类型发生变化,即不会覆盖基类型的同名方法。
41. 在使用自限定类型时,在导出类中只有一个方法,并且这个方法接受导出类型而不是基类型作为参数。如果不使用自限定,将重载参数类型。如果使用了自限定,只能获得某个方法的一个版本,它只能接受确切的参数类型。
42. 动态类型安全,比如:Collection的checkedList()方法。受检查的容器在试图插入类型不正确的对象时抛出ClassCastException。将导出类的对象放入将要检查基类型的收检查容器中是没问题的。
43. 由于擦除的原因,将泛型用于异常很受限。Catch语句不能捕获泛型类型的异常,因为在编译期和运行时都得知道异常的确切类型。但是,类型参数可以在方法的throws字句中用到,这使得可以编写随检查型异常而发生改变的泛型代码。如果不能参数化所抛出的异常,那么由于检查型异常的缘故,将不能编写这种泛化代码。
44. 混型最基本的概念是混合多个类的能力,以产生一个可以表示混型中所有类型的类。价值之一是可以将特性和行为一致地用于多个类之上。
45. 在C++中,混型就是继承自其参数类型的类,但Java由于擦除会忘记基本类型,所以泛型类不能直接继承自一个泛型参数。
46. 可以使用接口加上代理来达到混型的效果。
47. 可以使用装饰器模式。装饰器是通过使用组合和形式化接口(可装饰物/装饰器层次结构)实现的,其明显缺陷是只能有效工作在装饰中的一层(最后一层)。
48. 与动态代理混合,所产生的类的动态类型将是已经混入的组合类型,每个混入的类都必须是某个接口的实现。
49. 因为擦除要求指定可能用到的泛型类型的边界,以安全地调用代码中的泛型对象上的具体方法。这是一种限制,因为必须限制泛型类型使用特定的接口。而潜在类型机制的语言只要求实现某个方法子集,而不是某个特定类或接口,从而放松了这种限制。
50. 有时候泛型不是必须的,可以用基类型来代替。
51. 使用反射能够实现潜在类型机制,真正实现泛型代码。
52. 类型标记技术是Java文献推荐的技术。
53. 可以用适配器仿真潜在类型机制。潜在类型机制创建了一个包含所需方法的隐式接口。如果我们手工编写了所需的接口,那么它可以解决问题。我们可以使用适配器来适配已有的接口,以产生想要的接口。
54. 策略设计模式,将“变化的事物”完全隔离到了一个函数对象中。函数对象就是在某种程度上行为像函数的对象——一般会有一个相关的方法。函数对象的价值在于,与普通方法不同,可以传递出去,并且还可以拥有在多个调用之间持久化的状态。函数对象的目的是创建某种事物,使它的行为就像一个可以传递出去的单个方法一样。书中大量出现了将函数对象应用于序列上的泛型方法。
55. 泛型机制最吸引人的地方是使用容器类的地方。对于容器类来说,持有操作简单,但是操作其泛型类型的泛化代码不容易。