对Java继承的一些思考-构造函数

Java的继承,相信对于Java开发者来说,再熟悉不过了。但是如果要深入理解Java的继承,还是需要细细去分析的。所以,我写了这篇博客,记下自己对Java继承的一些理解和思考。

一、继承的语法

Java继承主要通过extends关键字实现。其格式如下:

// 父类Animal类
public class Animal {

}

// 子类Dog类,继承自Animal类
public class Dog extends Animal {

}

继承的语法十分简洁。继承了父类以后,子类就拥有父类的一些特性了。

二、构造函数

构造函数是类实例化的入口,Java的构造函数,与类名同名:

public class Animal {
  // 构造函数
  public Animal(Sting name) {
  }
}

另外,Java类的构造函数支持重载:

public class Animal {
  public Animal(String name) {
    this(name, "男");
  }

  public Animal(String name, String sex) {
    System.out.println(name + "," + sex);
  }
}

子类要在构造函数中调用父类的构造函数,可使用super关键字:

public class Dog extends Animal {
  public Dog(String name, String sex, String type) {
    super(name, sex);
    System.out.println(type);
  }
}

子类必须直接或者间接调用父类的构造函数,间接调用是指用this调用自身构造函数,而this指向的构造函数已调用父类的构造函数:

public class Dog extends Animal {
  public Dog(String name, String sex) {
    // 间接调用父类构造函数
    this(name, sex, "金毛");
  }

  public Dog(String name, String sex, String type) {
    // 直接调用构造函数
    super(name, sex);
    System.out.println(type);
  }
}

在这里也许会有一个疑问,平时写继承的时候,我们不写构造函数,Java编译器也不会报错,像下面这个例子:

public class Dictionary extends Book {
  public void nextPage() {
  }
}
// 程序不报错
new Dictionary()

这是为什么呢?
其实,在类中如果没有写构造函数,Java会默认添加一个无参构造函数,如果这个类没有继承其他类,则该构造函数时一个空的构造函数;如果这个类继承自其它类,那么还会在该构造函数中添加super()。因此,上述例子实际上等价于如下代码:

public class Dictionary extends Book {
  // 没有构造函数时,Java自动添加
  public Dictionary() {
    super();
  }

  public void nextPage() {
  }
}
new Dictionary()

既然可以调用super()。那么可以推断出,父类一定也有一个无参构造函数:

public class Book {
  public Book() {
    // coding...
  }
  ...
}

或者不写构造函数,原理与其子类相同

public class Book {
  // 没有构造函数时,Java会自动添加一个无参构造函数
  ...
}

因此,在没有写构造函数的情况下,子类构造函数的创建以及父类构造函数的调用由Java自动完成了。
此外,子类的构造函数如果没有直接或间接调用父类构造函数,那么Java编译器会在该构造函数中自动添加super();

public class Animal {
  public Animal() {
    System.out.println("动物");
  }
}

public class Dog extends Animal {
  public Dog() {
    // 如果在子类构造函数中没有直接或间接调用父类构造函数,
    // 那么Java会在构造函数中自动添加super();
    // super();
    System.out.println("狗");
  }
  public Dog(String name, String sex) {
    // super();
    System.out.println(name + "," + sex);
  }
  new Dog();
  new Dog("LiHua","女");
}

上述代码执行以后,打印的结果为:

动物
狗
动物
LiHua,女

可以看出,大部分情况下,我们就算不写构造函数,Java编译器依然不会报错,因为Java会自动为类添加默认的构造函数。但是,某些条件下,不写会出现问题,请看下面的例子:

public class Animal {
  public Animal(String name) {
    System.out.println("动物");
  }
}

public class Dog extends Animal{
  public Dog() {
    System.out.println("狗");
  }
}

new Dog();

这时,编译器就会报错

Exception in thread "main" java.lang.NoSuchMethodError:Animal:method()V not found

那么,此时为什么会报错呢?
因为子类如果没有直接或间接调用父类构造函数时,Java会在子类构造函数自动添加super(),即调用父类无参构造函数;但是在本例子中,父类的构造函数并没有无参构造函数:

public class Animal {
  public Animal(String name) {
    System.out.println("动物");
  }
}

有人会问,Java不是会自动为Animal类添加一个无参构造函数吗?
因为在Animal类中已经有构造函数,只有在类中没有写构造函数的情况下,Java才会自动为类添加一个无参构造函数。
要解决上述错误,那么就要在子类显示调用父类构造函数:

public class Dog extends Animal {
  public Dog() {
    super("");
    System.out.println("狗");
  }
}

或者在父类添加无参构造函数:

public class Animal {
  public Animal() {
    System.out.println("动物");
  }
  
  public Animal(String name) {
    System.out.println("动物");
  }
}

你可能感兴趣的:(对Java继承的一些思考-构造函数)