1 继承
1.1 继承
继承是面向对象编程的三大特征之一,它让我们更加容易实现对于已有类的扩展、更加容易实现对于现实世界的建模。
继承有两个主要作用:
- 代码复用,更加容易实现类的扩展
- 方便建模
public class Test{
public static void main(String[ ] args) {
Student s = new Student("高淇",172,"Java");
s.rest();
s.study();
}
}
class Person {
String name;
int height;
public void rest(){
System.out.println("休息一会!");
}
}
class Student extends Person {
String major; //专业
public void study(){
System.out.println("在尚学堂,学习Java");
}
public Student(String name,int height,String major) {
//天然拥有父类的属性
this.name = name;
this.height = height;
this.major = major;
}
}
继承使用要点:
- 父类也称作超类、基类。子类:派生类等。
- Java 中只有单继承,没有像 C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
- Java 中类没有多继承,接口有多继承。
- 子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。
- 如果定义一个类时,没有调用 extends,则它的父类是:java.lang.Object。
1.2 instanceof
instanceof 是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回 true;否则,返回 false。
public class Test{
public static void main(String[ ] args) {
Student s = new Student("高淇",172,"Java");
System.out.println(s instanceof Person);
System.out.println(s instanceof Student);
}
}
输出都是true
1.3 继承树追溯
属性/方法查找顺序:(比如:查找变量 h)
- 查找当前类中有没有属性 h
- 依次上溯每个父类,查看每个父类中是否有 h,直到 Object
- 如果没找到,则出现编译错误。
- 上面步骤,只要找到 h 变量,则这个过程终止。
构造方法调用顺序:
构造方法第一句总是:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到 Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复。
2 组合
“组合”不同于继承,更加灵活。
“组合”的核心就是“将父类对象作为子类的属性”,然后,“子类通过调用这个属性来获得父类的属性和方法”。
public class Test{
public static void main(String[ ] args) {
Student s = new Student("高淇",172,"Java");
s.person.rest();//s.rest();
s.study();
}
}
class Person {
String name;
int height;
public void rest(){
System.out.println("休息一会!");
}
}
class Student /*extends Person*/ {
Person person = new Person();
String major; //专业
public Student(String name,int height,String major) {
//天然拥有父类的属性
this.person.name = name;//this.name = name;
this.person.height = height;//this.height = height;
this.person.rest();
this.major = major;
}
}
继承只能有一个父类,但是组合可以有多个属性。
对于“is -a”关系建议使用继承,“has-a”关系建议使用组合。
Student is a Person 这个逻辑没问题,但是:Student has a Person
就有问题了。这时候,显然继承关系比较合适。