抽象类、final关键字、多态

时间:2021-08-29 08:25:41

1.1 抽象

1.1.1 抽象类概念

C extends B,B extends A,在继承过程中,形成一个继承金字塔,位于金字塔底部的类越来越具体(强大),位于塔顶的越来越抽象(简单)。

例如:人继承于动物,鱼继承于动物。人有睡觉(闭眼睡)的方法,鱼有睡觉的方法,动物也有睡觉的方法,

当一个类中的方法过于抽象时,实现不确定如何实现,此时可以把该方法定义成抽象方法。

抽象方法所在的类过于抽象,称为抽象类(abstract class)

public abstract class 类名 {

}

1.1.2 抽象类的特性

[1] 抽象类过于抽象,实例化后无语义 => 不能实例化

public abstract class Animal{

private String name;

public void setName(String name){

this.name = name;

}

public String getName(){

return this.name;

}

public Animal(){

}

public Animal(String name){

this.name = name;

}

public void sleep(){

}

}

抽象类、final关键字、多态

[2] 如果一个方法过于抽象无法实现,需要把该方法声明为抽象方法。形式

public abstract void sleep();

抽象方法一定位于抽象类中。

抽象方法没有方法体。

抽象类中的方法不一定都是抽象方法。

public abstract class Animal{

private String name;

public void setName(String name){

this.name = name;

}

public String getName(){

return this.name;

}

public Animal(){

}

public Animal(String name){

this.name = name;

}

public abstract void sleep();

}

子类继承抽象类,一定要根据自身情况重写抽象类的抽象方法,除非子类也是抽象类。

public class Person extends Animal{

/*

public void sleep(){

System.out.println("闭眼躺着睡觉...");

}

*/

}

抽象类、final关键字、多态

1.1.2 重写和实现

重写(override):子类继承父类的方法时不能满足自身需要时,子类重写父类的同名方法。

实现(implement):子类继承抽象父类时,一定要重写父类的抽象方法,此时父类的抽象方法没有方法体,也即没有实现;子类一定重写父类的抽象方法也即实现了父类的抽象方法。

实现是一种特殊的重写。实现建立在重写的继承上。

1.2 Final 关键字

final 是一个java的关键字,用于修饰局部变量、属性、方法、类,表示最终的意思。

[1] final修饰类表示最终类,无法被继承。

public final class Animal{

}

public class Person extends Animal{

public void sleep(){

System.out.println("闭眼躺着睡觉...");

}

}

抽象类、final关键字、多态

[2] final修饰符方法,方法就不能被重写。

public final void sleep(){

System.out.println("animal:sleep");

}

抽象类、final关键字、多态

[3] final 修饰属性,经常和static搭配使用,形成静态常量。

public static final String SEX_MALE = “Q仔”;

public static final String SEX_FEMALE = “Q妹”;

[4] final修饰变量

final 修饰基本数据类型 ,表示a中的内容(值)不能被改变

final int a = 10;

final 修饰引用数据类型,表示person中的内容(地址)不能被概念

public class Test01{

public static void main(String[] args){

final Person person = new Person();

person.sleep();

person = new Person();

person.sleep();

}

}

思考:

[1] 静态方法能被继承吗?

[2] 静态方法可以被重写吗?

java中静态属性和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏。

1)

静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成对,不需要继承机制及可以调用。如果子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。如果你想要调用父类的静态方法和属性,直接通过父类名.方法或变量名完成,至于是否继承一说,子类是有继承静态方法和属性,但是跟实例方法和属性不太一样,存在"隐藏"的这种情况。
2)

多态之所以能够实现依赖于继承、接口和重写、重载(继承和重写最为关键)。有了继承和重写就可以实现父类的引用指向不同子类的对象。重写的功能是:"重写"后子类的优先级要高于父类的优先级,但是“隐藏”是没有这个优先级之分的。

3)

静态属性、静态方法和非静态的属性都可以被继承和隐藏而不能被重写,因此不能实现多态,不能实现父类的引用可以指向不同子类的对象。非静态方法可以被继承和重写,因此可以实现多态。

1.3 多态

软件设计原则—开闭原则

对拓展开放,对修改关闭。

为什么要使用多态?

对系统进行业务拓展,增加系统的可维护性。

1.3.1 多态的概念

多态(?)

同一个行为具有多个不同表现形式或形态的能力。

可以理解为多种状态/多种形态

抽象类、final关键字、多态

同一份文档,由于使用的打印机不同,产生的结果不同

同一事物,由于条件不同,产生的结果不同

 

程序中的多态

同一引用类型,使用不同的实例而执行结果不同的。

同:同一个类型,一般指父类。

不同:不同的子类实例

不同:针对同一方法执行的结果不同

package cn.sxt05;

public class Test01 {

public static void main(String[] args) {

// 多态

// 同一引用类型

Pet pet = null;

// 父类引用 引用 子类对象

pet = new Dog("二狗",100,0,"土狗");

// 呈现多态

pet.eat();

pet = new Penguin("大脚", 90, 50, Penguin.SEX_FEMALE);

// 呈现多态

pet.eat();

}

}

实现多态的步骤

[1] 编写父类

[2] 编写子类,子类一定要重写/实现父类的方法

[3] 运行时,父类类型 引用 子类对象 (Pet pet = new Dog())

1.3.2 多态的实现形式

[1] 父类类型 引用 子类对象(本质)

// 多态

// 同一引用类型

Pet pet = null;

// 父类引用 引用 子类对象

pet = new Dog("二狗",100,0,"土狗");

// 呈现多态

pet.eat();

pet = new Dog() 父类类型引用子类对象,当调用eat方法时,执行的是被子类对象重写/实现的eat方法。

[2] 父类作为方法形参实现多态

public void feed(Pet pet) {

System.out.println(this.getName() + "正在喂" + pet.getName());

pet.eat();

}

[3] 父类作为方法的返回值实现多态

public Pet adoptPet(int type) {

Pet pet = null;

if(1 == type) {

pet = new Dog();

}else if(2 == type) {

pet = new Penguin();

}else if(3 == type){

pet = new Cat();

}

return pet;

}

1.4 类型转换

在多态中存在两种类型转换,一种是自动类型转换,一种是强制类型转换。

在引用数据类型转换过程中,

自动类型转换也称向上类型转换。子类可以自动转换成父类。

Pet pet = null;

pet = new Dog();

强制类型转换也称向下类型转换。父类可以强制转换成子类。

子类类型 引用 = (子类)父类对象

一般而言,需要判断父类对象的真实类型,用instanceof关键字

obj instanceOf 类/接口 判断obj是否是类/接口的实例

public class TestInstanceOf {

public static void main(String[] args) {

Dog dog = new Dog();

System.out.println(dog instanceof Dog); //true

System.out.println(dog instanceof Pet); //true

System.out.println(dog instanceof Object); //true

}

}

如果要调用子类特有的方法时,一定要强制类型转换,通过instanceof鉴别具体类型

public void play(Pet pet) {

if(pet instanceof Dog) {

Dog dog = (Dog) pet;

dog.catchFlyDisc();

}else if(pet instanceof Penguin) {

Penguin penguin = (Penguin) pet;

penguin.swimming();

}

}

1.5 调试技巧

step over: 抽象类、final关键字、多态 单步调试,一次只执行一行代码。

step into: 抽象类、final关键字、多态进入方法调试

step return:抽象类、final关键字、多态 返回/结束方法

抽象类、final关键字、多态:停止调试