课后作业4动手实验1
动手实验:继承条件下的构造方法调用
class Grandparent { public Grandparent() { System.out.println("GrandParent Created."); } public Grandparent(String string) { System.out.println("GrandParent Created.String:" + string); } } class Parent extends Grandparent { public Parent() { //super("Hello.Grandparent."); System.out.println("Parent Created"); // super("Hello.Grandparent."); } } class Child extends Parent { public Child() { System.out.println("Child Created"); } } public class TestInherits { public static void main(String args[]) { Child c = new Child(); } }
未取消注释前代码的运行结果:
GrandParent Created.
Parent Created
Child Created
取消第一行注释:
GrandParent Created.String:Hello.Grandparent.
Parent Created
Child Created
取消第二行注释:IDEA会报错
结论:通过 super 调用基类构造方法,必须是子类构造方法中的第一个语句。
思索:为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?
原因:子类的构造方法在运行之前必须调用父类的构造方法,这是因为子类继承了父类,它包含了父类的属性和方法。通过调用父类的构造方法,子类可以初始化父类继承的属性和状态。如果我们不调用父类的构造方法,那么父类的属性将无法得到初始化,可能会导致子类在使用父类属性时出现错误。总之,调用父类的构造方法是为了保证父类属性的正确初始化,而无法直接调用子类的构造方法是因为子类的属性和状态还未初始化,无法被父类使用。
扩展:不允许继承的类:final class 类名 { }
以final声明的方法不允许覆盖。 以final声明的变量不允许更改。 利用final,可以设计出一种特殊的“只读” 的“不可变类”。
创建“不可变的类”的对象后,此对象的属性不可改,而且也无法从此类派生出新子类。
String就是一个典型的例子。 不可变的“类”有何用? 可以方便和安全地用于多线程环境中, 访问它们可以不用加锁,因而能提供较高的性能。
JDK中的实例:String
不可变类的实例:Address.java
public final class Address { private final String detail; private final String postCode; //在构造方法里初始化两个实例属性 public Address() { this.detail = ""; this.postCode = ""; } public Address(String detail , String postCode) { this.detail = detail; this.postCode = postCode; } //仅为两个实例属性提供getter方法 public String getDetail() { return this.detail; } public String getPostCode() { return this.postCode; } //重写equals方法,判断两个对象是否相等。 public boolean equals(Object obj) { if (obj instanceof Address) { Address ad = (Address)obj; if (this.getDetail().equals(ad.getDetail()) && this.getPostCode().equals(ad.getPostCode())) { return true; } } return false; } public int hashCode() { return detail.hashCode() + postCode.hashCode(); } }