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("动物");
}
}