Java编程思想之泛型

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.  边界声明了T为A的类型或子类型,若A有函数f,则可以在使用这个边界类型参数的类中调用f。

16.  泛型类型参数将擦除到它的第一个边界,它可能有多个边界。.T擦除到A,就好像在类的声明中用A替换T一样。

17.  擦除是泛型实现的一种折中。泛型类型只有在静态类型检查期间才出现,在此之后,程序中所有泛型类型都被擦除,替换为它们的非泛型上界,若未指定,则被擦除成Object。擦除的核心动机是它使得泛化的客户端可以使用非泛化的类库。这称为迁移兼容性。

18.  擦除主要正当理由是从非泛化代码到泛化代码的转变过程,以及在不破坏现有类库的情况下,将泛型融入Java语言中。泛型不能用于显示地引用运行时类型的操作中,因为所有关于参数的类型信息都丢失。使用泛型不是强制的。

19.  在泛型中创建数组,使用Array.newInstance()是推荐的方式。

20.  因为擦除在方法体中移除了类型信息,所以在运行时的问题就是边界:即对象进入和离开方法的地点,这些正是编译器在编译期执行类型检查并插入转型代码的地点。

21.  泛型中的所有动作都发生在边界处,对传递进来的值进行额外的编译期检查,并插入对传递出去的值的转型。有助于澄清对擦除的泛型。

22.  通过引入类型标签来对擦除进行补偿。这意味着需要显示传递类型的class对象,以便可以在类型表达式中使用它。编译器将确保类型标签匹配泛型参数。

23.  成功创建泛型数组的唯一方式就是创建一个被擦除类型的新数组,然后对其转型。

24.  没有任何方式可以推翻底层的数组类型。只有通过改变擦除类型的边界,才能在初始化泛型类型参数时,相应改变数组的类型。

25.  边界使得可以在用于泛型的参数类型上设置限制条件,但更重要的效果是可以按照边界类型来调用方法。通配符?被限制为单一边界。

26.  Listflist = new ArrayList(); 这里唯一的限制是这个List要持有某种具体的Fruit和Fruit的子类型,但不知道具体类型,所以不能添加任何类型对象到里面。如果调用一个返回Fruit的方法则是安全的,因为知道这个List至少拥有Fruit类型。

27.  编译器将直接拒绝对参数列表中涉及通配符的方法的调用。编译器只关注传递进来和要返回的对象类型。

28.  超类型通配符,声明通配符是由某个特定类的任何基类来界定的。这样向容器添加子类或者class类是安全的。这里get的安全类型只能是Object。

29.  无界通配符可以被认为是一种修饰,好像等价使用了原生类型。可以用在处理多个泛型参数的情形。

30.  List实际上是List。List表示持有任何Object类型的原生List,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>,将使用class B extends A和class C extends A。强制要求将正在定义的类当作参数传递给基类。能够保证类型参数必须与正在定义的类相同。不能传递不是自限定类型的参数到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.  泛型机制最吸引人的地方是使用容器类的地方。对于容器类来说,持有操作简单,但是操作其泛型类型的泛化代码不容易。

你可能感兴趣的:(Java学习)