slacr_

Just to record my life and thoughts.
笔记/编程/杂乱/极简

[Java笔记]继承&多态

May 9, 2023Java1893 words in 13 min

继承

定义类时若缺省extends 关键字,则所定义的类为java.lang.Object类的直接子类.
Java 仅支持单重继承,即一个类至多只有一个直接父类。在Java 中可以通过接口实现其他语言中的多重继承。

覆盖(overriding)

@Override 注解表示其后的方法必须是覆盖父类的一个方法。如果具有该注解的方法没有覆盖父类的方法,编译器将报告一个错误。
父类中static方法可以被继承,但不能被覆盖。
要在子类中定义一个覆盖的方法,方法的参数和返回值类型都必须与父类中的方法相同。

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
public class Base {
public int pr_1;
Base() {};
Base(int pr_1) {this.pr_1 = pr_1;}
public void say(){
System.out.println(pr_1 + "_from base");
}
}

public class Derived extends Base {
public int pr_1;
Derived() {};
Derived(int pr_1) {this.pr_1 = pr_1;}
@Override
public void say() {
System.out.println(pr_1 + "_from derived");
}
}

public class Main {
public static void main(String[] args) {
Base b = new Base(1);
Derived d = new Derived(2);
d.say(); // 2_from derived
}
}

super关键字

引用当前对象的父类对象.

this():调用本类中其他重载的构造函数(必须写在函数中的第一行)
super():调用父类中的构造函数(必须写在函数中的第一行)
它们不能存在于同一个构造方法中

this.XXX():调用在本类中重写的父类方法
super.XXX():调用父类中的方法
它们可以存在于同一个构造方法中

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
public class Base {
public int pr_1;
Base() {};
Base(int pr_1) {
this.pr_1 = pr_1;
System.out.println("Base constructor");
}
public void say(){
System.out.println(pr_1 + "_from base");
}
}

public class Derived extends Base {
public int pr_1;
Derived() {};
Derived(int pr_1) {
super(); // 构造父类构造
super.pr_1 = 100; // 访问父类成员
this.pr_1 = pr_1;
System.out.println("Derived constructor");
}
@Override
public void say() {
System.out.println(pr_1 + "_from derived");
}

public void baseSay() {
super.say(); // 调用父类方法
}
}

public class Main {
public static void main(String[] args) {
Base b = new Base(1);
Derived d = new Derived(2);
d.baseSay();
}
}

// Base constructor
// Derived constructor
// 100_from base

访问修饰符

Java 类有 两种访问权限, public 和 缺省, public 权限可以供类外访问, 缺省只能包内访问.

类的成员有四种访问权限 private 缺省 protected public.
private只能类内访问; 缺省本类和同一个包中的类可以访问; protected 可以被这个类本身、同一
个包中的类以及该类的子类访问; public 被任何类访问.

抽象类(abstract class)

抽象方法只有方法的声明,没有方法的实现包含抽象方法的类必须定义为抽象类,定义抽象类需要的类前加上abstract修饰符。
在抽象类中可以定义构造方法,这些构造方法可以在子类的构造方法中调用。尽管在抽象类中可以定义构造方法,但抽象类不能被实例化,即不能生成抽象类的对象。
在抽象类中可以定义非抽象的方法。可以创建抽象类的子类,抽象类的子类还可以是抽象类,只有非抽象的子类才能使用new创建该类的对象。
抽象类的非抽象子类必须实现父类的抽象方法.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class Person {
public Person(){}
public Person(int age, String name) { this.name = name; this.age = age;}
public int age;
public String name;
public abstract void intro(); // 抽象方法没有实现
}

public class Programmer extends Person {
public Programmer(String name, int age) { super(age, name);} // 调用父类构造方法
public void intro() { // 实现父类抽象方法
System.out.println("I am a " + this.getClass().getSimpleName() + ", and my name is "+ name + ", " + age + " years old.");
}
}

public class Main {
public static void main(String[] args) {
Programmer slacr = new Programmer("slacr", 19);
slacr.intro();
}
}

// I am a Programmer, and my name is slacr, 19 years old.

对象转换

子类对象和父类对象在一定条件下也可以相互转换,这种类型转换一般称为对象转换或造型 (casting)。对象转换也有自动转换和强制转换之分.
子类对象可以作为父类对象使用. 和C++中一样. 这种转换称为向上转换 (up casting)。向上转换指的是在类的层次结构图中,位于下方的类(或接口)对象都可以自动转换为位于上方的类(或接口)对象.
也可以将一个父类对象转换成子类对象,这时需要使用强制类型转换。强制类型转换需要使用转换运算符"()"。

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
public class Father {
public int salary;
Father(int salary){
this.salary = salary;
System.out.println("Father.parametric_constructor");
}
Father() {
System.out.println("Father.default_constructor");
this.salary = 0;
}
public void work() {
System.out.println("This is the 996 foobar" + ", from which I could get " + salary + " a month.");
}
}

public class Son extends Father{
public int score;
public Son() {
this.score = score;
System.out.println("Son.default_constructor");
}
public Son(int score) { // 子类没写super(), 会自动调用父类的无参构造
this.score = score;
System.out.println("Son.parametric_constructor");
};
public void doExam(){
System.out.println("I got " + score + ", but I hate exam.");
}
}


public class Main {
public static void main(String[] args) {
Father f = new Father(3000);
Son s = new Son(100);
f.work();
s.doExam();
Father ff = s; // 父类接受子类对象, 自动隐式类型转换
ff.work(); // 在构造子类时调用的父类是无参构造, salary = 0;
Son ss = (Son)f; // 父类强制显示转换为子类, 写法没问题, 但不能完成转换,异常
ss.doExam(); // 无法调用

}
}

instanceof 运算符

测试一个实例是否是某种类型的实例.

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
Father f = new Father(3000);
Son s = new Son(100);
System.out.println( s instanceof Father );
System.out.println( f instanceof Father );
System.out.println(s instanceof Object);
System.out.println(f instanceof Son);
//true
//true
//true
//false
}

多态与动态绑定

多态 (polymorphism) 就是多种形式,是指Java 程序中一个类或多个类中可以定义多个同名方法,这多个同名方法完成的操作不同.
Java 语言支持两种类型的多态:
(1)静态多态:也叫编译时多态,是通过方法重载实现的。
(2)动态多态:也叫运行时多态,是通过方法覆盖实现的。

将方法调用与方法体关联起来称方法绑定 (binding)。若在程序执行前进行绑定,叫前期绑定.若在程序运行时根据对象的类型进行绑定,则称后期绑定或动态绑定。Java 中除static方法和 final方法外都是后期绑定.

对重载的方法,Java运行时系统根据传递给方法的参数个数和类型确定调用哪个方法,而对覆盖的方法,运行时系统根据实例类型决定调用哪个方法。对子类的一个实例,如果子类覆盖了父类的方法,运行时系统调用子类的方法,如果子类继承了父类的方法,则运行时系统调用父类的方法.

知识点

  1. final 修饰的 class不能被继承, 其中的方法隐含为final修饰 ; final修饰的方法不能被重写; final修饰的变量不可更改.

参考

  1. 《Java程序设计(第3版)》 IBSN 9787302485520
  2. Java API 文档
  • Author:

    slacr_

  • Copyright:

  • Published:

    May 9, 2023

  • Updated:

    May 9, 2023

Buy me a cup of coffee ☕.

1000000