java 重写的 几大注意点

Posted jonalin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 重写的 几大注意点相关的知识,希望对你有一定的参考价值。

Single Dispatch

class Parent 
  void print(String a)  log.info("Parent - String"); 
  void print(Object a)  log.info("Parent - Object"); 

 
class Child extends Parent 
  void print(String a)  log.info("Child - String"); 
  void print(Object a)  log.info("Child - Object"); 
String string = "";
Object stringObject = string;
 
// What gets printed?
Child child = new Child();
child.print(string);
child.print(stringObject);
 
Parent parent = new Child();
parent.print(string);
parent.print(stringObject);
child.print(string);        // Prints: "Child - String"
child.print(stringObject);  // Prints: "Child - Object"
 
parent.print(string);       // Prints: "Child - String"
parent.print(stringObject); // Prints: "Child - Object"

被调用的方法取决于“实际”实例类型,而不是“声明的”实例类型。

Java 不支持双调度,因此,在处理方法参数时,重要的是参数的“声明”类型,而不是其“实际”类型。

双调度是根据接收器和参数类型选择在运行时调用的方法的过程的技术术语。(可以使用访问者模式达到一样的效果)

Hidden Override

class Parent 
  void print(Object a)  log.info("Parent - Object"); 

 
class Child extends Parent 
  void print(String a)  log.info("Child - String"); 
String string = "";
Parent parent = new Child();
parent.print(string);
parent.print(string);  // Prints: "Parent - Object"

在检查子类覆盖之前,Java 首先会选择要调用的方法。 在这种情况下,声明的实例类型是 Parent ,Parent 中唯一匹配的方法是 Parent :: print(Object)。 当Java然后检查 Parent :: print(Object) 的任何潜在覆盖时,它找不到任何覆盖,因此这是执行的方法。

Exposed Override

class Parent 
  void print(Object a)  log.info("Parent - Object!"); 
  void print(String a)  throw new RuntimeException(); 

 
class Child extends Parent 
  void print(String a)  log.info("Child - String!"); 
String string = "";
Parent parent = new Child();
parent.print(string);
parent.print(string);  // Prints: "Child - String!"

Ambiguous Parameter

class Foo 
  void print(Cloneable a)  log.info("I am cloneable!"); 
  void print(Map a)  log.info("I am Map!"); 
HashMap cloneableMap = new HashMap();
Cloneable cloneable = cloneableMap;
Map map = cloneableMap;
 
// What gets printed?
Foo foo = new Foo();
foo.print(map);
foo.print(cloneable);
foo.print(cloneableMap);
foo.print(map);           // Prints: "I am Map!"
foo.print(cloneable);     // Prints: "I am cloneable!"
foo.print(cloneableMap);  // Does not compile

不编译,因为有多个方法对给定参数同样有效。

Multiple Inheritance – Interfaces

interface Father 
  default void print()  log.info("I am Father!"); 

 
interface Mother 
  default void print()  log.info("I am Mother!"); 

 
class Child implements Father, Mother 
new Child().print();

不编译,因为 Father 和 Mother 存在冲突的默认方法

Multiple Inheritance – Class and Interface

class ParentClass 
  void print()  log.info("I am a class!"); 

 
interface ParentInterface 
  default void print()  log.info("I am an interface!"); 

 
class Child extends ParentClass implements ParentInterface 
new Child().print();  // Prints: "I am a class!"

如果类和接口之间存在继承冲突,则类获胜。

Transitive Override

class Parent 
  void print()  foo(); 
  void foo()  log.info("I am Parent!"); 

 
class Child extends Parent 
  void foo()  log.info("I am Child!"); 
new Child().print();  // Prints: "I am Child!"

覆盖方法对传递调用也会生效。如果方法被覆盖,那么 Parent :: print 将调用被覆盖的 foo() 版本。

Private Override

class Parent 
  void print()  foo(); 
  private void foo()  log.info("I am Parent!"); 

 
class Child extends Parent 
  void foo()  log.info("I am Child!"); 
new Child().print();  // Prints: "I am Parent!"

Parent.foo() 被声明为私有。 因此,当 Parent.print() 调用 foo() 时,它被硬编码为Parent.foo()。 无论子类中是否有 foo() 的其他实现或者调用 print() 的实例的实际类型。

Static Overrides

class Parent 
  static void print()  log.info("I am Parent!"); 

 
class Child extends Parent 
  static void print()  log.info("I am Child!"); 
Child child = new Child();
Parent parent = child;
 
parent.print(); // Prints: "I am Parent!"
child.print();  // Prints: "I am Child!"

Java 不允许重写静态方法。如果在父类和子类中都定义了相同的静态方法,则实例的实际类型根本不重要。只有声明的类型用于确定调用两个方法中的哪一个。

Static Linking

class Parent 
  void print()  staticMethod(); instanceMethod(); 
  static void staticMethod()  log.info("Parent::staticMethod"); 
  void instanceMethod()  log.info("Parent::instanceMethod"); 

 
class Child extends Parent 
  static void staticMethod()  log.info("Child::staticMethod"); 
  void instanceMethod()  log.info("Child::instanceMethod"); 
Child child = new Child();
child.print();
Parent::staticMethod
Child::instanceMethod

对于实例方法,即使调用者在父级中,覆盖也会生效。 但是,对于静态方法,即使变量的声明类型是 Child,由于中间的 print() 方法,也会调用 Parent :: staticMethod

Wrapping up

  • 始终使用 @Override 注释标记所有覆盖方法
  • 始终使用类引用而不是实例引用来调用静态方法
  • 设置 IDE 或 lint 错误提醒以强制执行上述和其他代码检测
  • 使用组合而不是继承

以上是关于java 重写的 几大注意点的主要内容,如果未能解决你的问题,请参考以下文章

java动态绑定的一点注意

C++ 重写虚函数的代码使用注意点+全部知识点

Akka框架使用注意点

注意重写类的equals()方法

开源项目几点心得,Java架构必会几大技术点

Java架构必会几大技术点(转)