java学习笔记 [3] 继承 & 多态篇

java学习笔记的第三篇,内容主要有继承和多态

#继承

#关键字

关键字 extends 表示继承,继承是一个 is-a 关系,java 中只有公有继承

#覆盖方法(override)

将父类中的方法在子类中重新定义,以 Employee 类和 Manager 类为例,Manager 继承 Employee 类,Employee 有方法 getSalary(); Manager 类需要重写这个方法,加上经理所特有的奖金。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class Employee{
	private double salary;
	...
	public double getSalary(){
		return salary;
	}
}

public class Manager extends Employee{
	private double bonus;
	...
	public double getSalary(){
		//return salary + bonus;  // 错误,不能访问超类的私有域
		//return getSalary() + bonus;  // 错误,调用自身直至崩溃
		return super.getSalary() + bonus;  // 正确
	}
}
//super关键字表示调用父类的方法

#子类构造器

必须调用父类的构造器,并且应将这一过程放在程序的第一句

1
2
3
4
public Manager(String name, String id, double salary){
	super(name, id, salary);  // 置于第一句,如果没有这句,系统自动调用父类的默认构造函数;如果没有默认构造函数有没有显式调用其他构造器就会产生错误
	bonus = 0;
}

#接口

java不支持多继承,即每一个类都只能继承最多一个类。但每一个类可以实现多个接口,这也是引入接口的一个考虑。

#多态

java 实现多态的两种方式:重载(overloading)和覆盖(override)

 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
/* override */
Manager boss = new Manager("lihui", 201822, 50000);
boss.setBonus(20000);

Empolyee[] staff = new Empolyee[2];
staff[0] = boss;
staff[1] = new Employee("chengle", 201833, 60000);

staff[0].setBonus(20000);  // 错误,staff声明为Employee类型,Employee没有setBonus方法

if(staff[0] instanceof Manager)
	((Manager)staff[0]).setBonus(20000);  // 正确,将staff[0]强制转换为Manager类型
	
for(Employee aEmpolyee: staff)
	System.out.println(aEmpolyee.getName() + " " + aEmpolyee.getSalary());
// aEmpolyee定义为Empolyee类型,但在执行的时候,aEmpolyee引用的Empolyee和Manager调用不同的getSalary函数
// 一个对象变量可以指示多种实际类型的现象称为多态。
// 在运行的时候自动选择调用哪个方法称为动态绑定。

/* overloading */
public class Manager{
	...
	public double getSalary(String name){...}
	public float getSalary(String name){...}  //错误,已经存在getSalary(String name)方法,即签名相同,说明重载与返回值无关
	public double getSalary(String name, String id){...}  //正确的重载
}

方法的签名:方法的名字和参数列表称为方法的签名,返回类型不是签名的一部分。

override 的规则:

  • 子类覆盖父类中具有相同签名的方法。
  • 返回类型是被重写方法的返回类型的子类型。
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 staticprivatefinal的方法不能被重写。(private 的方法本身就被定义成了final 的)
  • 构造器不能被重写。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。

overloading 的规则:方法名相同,参数列表必须不同,返回值可同可不同,修饰符可同可不同。

#方法调用的过程

1)假设调用 x.f(param), 编译器一一列举 x 所属类中的名为 f 的方法以及其父类中访问属性为 public 的名为 f 的方法(超类的私有方法不可访问)。

2)查看调用方法提供的参数类型。如果第一步中列举出的方法中有一个方法的参数列表与提供的参数类型完全匹配,就选择这个方法。如果没有找到与参数类型匹配的方法或者经过类型转换后有多个方法与之匹配,就会产生错误。

3)如果是 staticprivatefinal 方法或者构造器,编译器可以准确的知道应该调用哪个方法,静态绑定。

4)动态绑定时,先查看子类中是否定义了这个方法,是则调用,否则调用父类的这个方法。

#final 修饰符

定义类的时候加上 final 修饰符表示类不允许被继承,其中的方法自动的成为 final,但是域不会变成 final。一个方法或者一个域也可以加上 final 表示不可被覆盖或者不可改变域的值。

#抽象类

关键字 abstract 表示抽象类,包含有一个或多个抽象函数的类需要声明为抽象类(为了代码清晰),抽象类里的抽象方法不需要实现,在子类中对其进行实现。

updatedupdated2022-05-032022-05-03