# 继承

继承是面向对象的第二大特性,它可极大地提高代码复用。来看实例:

public class Person {
    private String name;
    public int age;
    protected int score;

    public Person() {
        System.out.println("this is Person default constructor!address:"+this);
    }

    public Person(String name) {
        this();
        this.name = name;
    }

    public Person(String name, int car_ID) {
        super();
        this.name = name;
        Car_ID = car_ID;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    int Car_ID;

    public void GetInCar(int car_id) {
        Car_ID = car_id;
    }

}

class Student extends Person{
    public Student() {
        System.out.println("this is Student default constructor!address:"+this);
    }

    public Student(String name) {
        //super();
        super(name);
        System.out.println("name:"+name);
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Instance p1:");
        Person p1 =new Person();
        System.out.println("Instance stu1:");
        Student stu1 = new Student();
        System.out.println("Instance stu2:");
        Student stu2 = new Student("xie");
        System.out.println("stu2's name:"+stu2.getName());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

继承有一些限制:

  • 如果不指定,子类实例化的时候先调用父类的默认构造方法。如果不想调用默认构造方法可以使用super(参数)来指定要调用的父类构造函数,但该语句必须放在构造方法的第一行。
  • 一个子类只能继承一个父类,但是继承层次是不限制的,如果想让C继承A和B,可以让B继承A,让C继承B,这样C就可以同时使用A和B的特性,这只算是小道方法。如果想继承多个类,可以使用接口。
  • 一个子类继承父类时会继承所有的属性和方法,但是所有非私有属性和方法属于显式继承,所有私有属性和方法属于隐式继承。比如上面的name属性,在子类中可通过getter和setter方法操作,但不能直接操作。

# 重写

在类继承结构中,当子类继承父类中的方法无法满足子类设计需求时,可以针对已有方法进行扩充,此时子类中定义的方法与父类中的方法名称,返回值类型,参数类型及个数完全相同,这就叫做重写(overriding)。

提起重写,就会说到重载(overloading),它们都属于面向对象多态性的形式,重载是同一个类中,方法名称相同,但是参数类型及个数不同的一组方法。

来看下方法重写实例:

public class Person {
    private String name;
    protected String sentence;

    public Person() {
        //System.out.println("this is Person default constructor!address:" + this);
    }

    public Person(String name) {
        this();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    protected void Speak(String sentence) {
        System.out.println(name + " says:" + sentence);
        this.sentence=sentence;
    }

    private void MouthMove() {
        System.out.println("Person mouth is moving!");
    }

    public void SpeakAgain() {
        System.out.println(name + " again:");
        this.Speak(this.sentence);
        this.MouthMove();
    }

}

class Student extends Person {
    String sentense="world";
    public Student() {
        //System.out.println("this is Student default constructor!address:" + this);
    }

    public Student(String name) {
        // super();
        super(name);
        //System.out.println("name:" + name);
    }

    public void Speak(String sentence) {
        System.out.println(getName()+" answer:"+sentence);
        this.sentence=sentence;
        System.out.println(super.sentence+":"+this.sentense);
    }

    protected void MouthMove() {
        System.out.println("Student mouth is moving!");
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 =new Person("xie person");
        p1.Speak("hello");
        p1.SpeakAgain();

        Student stu1 = new Student("li student");
        stu1.Speak("hi");
        stu1.SpeakAgain();

        p1 = new Student("wang student");
        p1.Speak("hehe");
        p1.SpeakAgain();

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

注意:

  • 方法重写能让子类表现的同父类不一样,实现多态。方法是能重写的,属性感觉更多的像是在不同的作用域中。
  • 类中控制权限大小排序为private<default<protected<public,重写的时候子类的方法权限只能大于等于父类的控制权限。如果父类是private权限,那么子类是不能重写它的。
  • this调用属性或方法时,先从本类查找,如果没有再去寻找父类,而super调用时则直接去查找父类。

# final关键字

为了保护父类中的方法或属性,可以让其用final修饰:

  • final修饰的类,不会再被任何类继承。
  • final修饰的方法,不会再被重写。
  • 如果想在类中定义一些状态常量,可以用static final修饰,它们能被所有对象共用,且不能被修改。这些常量一般用大写。
  • final修饰的常量等同于前面说的静态常量池。
public class Person {
    protected static final String sentence="hello";

    public Person() {
        //System.out.println("this is Person default constructor!address:" + this);
        String str1 = "hello world";
        String str2 = sentence+" world";
        if(str1 == str2) {
            System.out.println("str1 == str2");
        }
    
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 多态

从上继承的例子中可以看出多态。多态分为:

  • 对象向上转型:将子类的实例赋值给父类引用,调用该引用时自动调用子类的重写方法。
  • 对象向下转型:调用子类扩充父类的功能,将已经发生对象向下转型的引用通过强制类型转换为子类引用,再调用这些功能。必须先发生向上转型,才可以进行向下转型。
public class Person {
    public void Speak() {
        System.out.println("Person is speaking!");
    }

    public void Teach() {
        System.out.println("Person is teaching!");
    }

}

class Student extends Person {
    @Override
    public void Speak() {
        System.out.println("Student is speaking!");
    }
    public void Learn() {
        System.out.println("Student is learning!");
    }

}

public class Main {
    public static void main(String[] args) {
        //对象向上转型
        Person p1 = new Person();
        p1.Speak();
        Person p2 = new Student();
        p2.Teach();
        p2.Speak();

        //对象向下转型
        Student stu1 = (Student)p2;
        stu1.Learn();

        System.out.println("stu1 instanceof Student:"+(stu1 instanceof Student));
        System.out.println("stu1 instanceof Person:"+(stu1 instanceof Person));
        System.out.println("p2 instanceof Student:"+(p2 instanceof Student));
        System.out.println("p2 instanceof Person:"+(p2 instanceof Person));
        System.out.println("p1 instanceof Student:"+(p1 instanceof Student));
        System.out.println("p1 instanceof Person:"+(p1 instanceof Person));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# Object类

Object是Java中唯一一个没有父类的类,所有class定义的类默认继承自Object类,该类定义了一个Java类应该有的一些公共方法。

方法名 用途
toString 该类转换为String时调用的
equals 比较两个对象,原本只是比较对象的内存地址,String类重写了该方法。
hashCode 返回唯一标识对象的哈希值
getClass 返回对象运行时类
getName 获取对象类的名称