继承
这里我们定义一个Person的类:
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
在定义一个Student类:
class Student {
private String name;
private int age;
private int score;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
public int getScore() { … }
public void setScore(int score) { … }
}
可以发现,这两个类中,有很多相同的字段和方法,那么我们可不可以在Sutdent类中不用再写相同的字段和方法,只写其特有的属性和方法呢?
当然可以! 但是,要用到java的 extends关键字,他表示继承。
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
class Student extends Person {
// 不要重复name和age字段/方法,
// 只需要定义新增score字段/方法:
private int score;
public int getScore() { … }
public void setScore(int score) { … }
}
这样我们就可以自写需要新增的代码。
注意:子类自动获得了父类的所有字段,严禁定义与父类重名的字段!
在OOP的术语中,我们把Person称为超类(super class)、父类(parent class)、基类(base class),把Student称为子类(subclass),扩展类(extended class)。
继承树
在编写父类,person的时候我们并没有,给person写extends。它同样会有一个继承关系,不过这个关系是java的机制中的默认继承关系,Java中默认Obect类为所有类的父类。
继承关系如下:

java只允许一个class继承一个父类。也就是说在java中的所有继承关系都是单继承。一个类有且只有一个父类。object类是特例,它没有父类。
我们再定义一个别的类时,继承树如下:

一个类可以被多个类继承,但是它只能继承一个父类。
继承中的字段修饰关系和普通的一样,有 private ,默认,protect和public。但是,继承中有个特点,就是子类无法访问父类的private字符或者private方法,
class Person {
private String name; //私有化字段
private int age; //私有化字段,不能被访问
}
class Student extends Person {
public String hello() {
return "Hello, " + name; // 编译错误:无法访问name字段
}
}
这样一来 ,继承的作用就削弱了,如果要访问字段,我们可以将private,改成protect。被这个关键字修饰的字段可以被子类访问。
class Person {
protected String name;
protected int age;
}
class Student extends Person {
public String hello() {
return "Hello, " + name; // OK!
}
}
super关键字
super关键字表示父类(超类)。子类引用父类的字段时,可以使用super.filedNama。
class Student extends Person {
public String hello() {
return "Hello, " + super.name;//这里可以不用spuer,用this.name 或则 name 也可以,编译器会自动定位到父类字段
}
}
但是,以下的这个时候就必须要用 super关键字。
class Person {
protected String name;
protected int age;
//定义个无参的构造方法
//public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
protected int score;
//直接运行会报错,因为编译器会自动给子类添加一个 sper();
// super();//但是父类并没有无参的构造方法,解决办法可以给父类添加一个无参的构造方法 或者 有suer(name,age);指定调用有参构造方法
public Student(String name, int age, int score) {
this.score = score;
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student("Xiao Ming", 12, 89);
}
}
可以得出一个结论:如果父类没有默认的狗杂方法,子类就必须显示的调用super()并且给出参数以便让编译器定位到父类的一个合适的构造方法。
这里也可以看出,子类不会继承父类的任何狗杂方法,子类默认的构造方法是编译器自己生成的,不是继承的。
区分继承和组合
在使用继承时,我们要注意逻辑一致性。
class Book {
protected String name;
public String getName() {...}
public void setName(String name) {...}
}
再写一个继承类、我们能不能让子类继承父类的 nama字段:
class Student extends Book {
protected int score;
}
显然,从逻辑上讲,这是不合理的,Student不应该从Book继承,而应该从Person继承。
究其原因,是因为Student是Person的一种,它们是is关系,而Student并不是Book。实际上Student和Book的关系是has关系。
具有has关系不应该使用继承,而是使用组合,即Student可以持有一个Book实例:
class Student extends Person {
protected Book book;
protected int score;
}
因此,继承是is关系,组合是has关系。
浙公网安备 33010602011771号