# 继承
继承是面向对象的第二大特性,它可极大地提高代码复用。来看实例:
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
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
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
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
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 | 获取对象类的名称 |