OCA/OCP Java Note (10): Class Design (2)

3. Implementing Interfaces

3.1. Defining an Interface

  1. 接口不能直接实例化。
  2. 一个接口中可以不包含任何方法。
  3. 接口不能标记为final。
  4. 顶层接口默认具有public或default的访问限制和abstract修饰符,将接口标记为private/protected/final会导致编译错误。此条不适用于内部接口。
  5. 接口中的所有非default方法默认具有abstract和public修饰符,将方法标记为private/protected/final会导致编译错误。关于default方法,可以参考这里

eg. 下面的两个接口的定义是等效的,编译器会把第一种自动转换为第二种形式。

3.2. Inheriting an Interface

  继承借口的规则为:

  1. 接口或抽象类可以继承接口,该接口或抽象子类会继承所有抽象方法,作为其自己的抽象方法。
  2. 实现接口(或继承了接口的抽象类)的直接具体子类,必须实现其继承的所有抽象方法。

  接口可以使用extends继承多个接口。抽象类可以使用implements实现多个接口,而不必给出实际的实现。

eg. 

3.2.1. Classes, Interfaces, and Keywords

  类可以实现接口,不能继承接口。接口可以继承接口,不能实现接口。

3.2.2. Abstract Methods and Multiple Inheritance

  如果一个具体类实现的两个接口中具有相同名称和签名的方法,具体类只需要给出一个实现。

eg. 

接口Herbivore和Omnivore都定义了 eatPlants() ,Bear实现了Herbivore和Omnivore,只需要给出一个 eatPlants() 的实现即可。
  如果一个具体类实现的两个接口中具有相同名称、不同签名的方法,具体类需要分别实现,相当于方法重载。

eg. 

  如果两个接口中具有相同名称和签名、不同返回类型的方法,具体类不能同时实现这两个接口。Java不允许定义两个名称和签名相同、而返回类型不同的方法。

eg. 

3.3. Interface Variables

  1. 接口中的变量是public、static和final的,将其标记为private或protected会导致编译错误。
  2. 由于接口中的变量是final的,变量必须在定义时赋值。

eg. 下面的两种定义是等效的,编译器会把第一种自动转换为第二种的形式。

3.4. Default Interface Methods

  Java 8中引入了默认方法,可以在接口中使用default关键词为抽象方法提供默认实现。

  1. 默认方法只能在接口中声明,不能在类和抽象类中声明。
  2. 默认方法必须标记为default,且必须提供实现。
  3. 默认方法不是static、final、abstract的,实现接口的类可以直接使用或重写默认方法。
  4. 默认方法是public的,标记为private或protected将无法编译。

3.4.1. Default Methods and Multiple Inheritance

  由于一个类可以实现多个接口,通过引入默认方法,基本上相当于引入了多继承。如果一个类实现的两个接口中,具有相同名称和签名的默认方法,将无法编译,因为Java不知道应该调用那个方法。

eg. 

  一个例外是,如果类重写了两个接口中具有相同名称和签名的默认方法,Java将使用该重写的方法,可以顺利编译。

eg. 

3.5. Static Interface Methods

  Java 8支持在接口中通过static定义静态方法,接口中的静态方法的特性和类中的静态方法基本一致,唯一的区别是,接口中的静态方法不会被任何实现该接口的类继承,由此避免了多继承的问题,即便一个类实现的两个接口具有相同名称和签名的静态方法,由于静态方法不会被继承,不会有编译错误。需要注意:

  1. 接口中静态方法是public的,使用private或protected将无法编译。
  2. 必须使用接口名来引用其中的静态方法。

4. Understanding Polymorphism

4.1. Casting Objects

  转换对象类型的规则为:

  1. 将对象从子类转换为父类,不需要显式地转换。
  2. 将对象从父类转换为子类,需要显式地转换。
  3. 编译器不允许转换到无关的类型。
  4. 如果被转换的对象不是目标类型的实例,运行时会抛出异常,尽管编译可以通过。

eg. 

将对象 rodent 转换为其子类Capybara,抛出ClassCastException异常。转换时应该使用如下的方法确保 rodent 是Capybara的实例:

4.2. Virtual Methods

  Java中所有非final、非static和非private的方法都可以看做是虚方法。

eg. 

输出为:

4.3. Polymorphic Parameters

  多态的一个重要应用是用来向方法传递子类或接口的实例。

eg.

输出为: