09(01)总结final,多态,抽象类,接口

时间:2022-05-04
本文章向大家介绍09(01)总结final,多态,抽象类,接口,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1:final关键字(掌握)

(1)是最终的意思,可以修饰类,方法,变量。

(2)特点:

A:它修饰的类,不能被继承。

B:它修饰的方法,不能被重写。

C:它修饰的变量,是一个常量。

/*

final可以修饰类,方法,变量

特点:

final可以修饰类,该类不能被继承。

final可以修饰方法,该方法不能被重写。(覆盖,复写)

final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。

常量:

A:字面值常量

"hello",10,true

B:自定义常量

 final int x = 10;
*/
//final class Fu //无法从最终Fu进行继承
class Fu {
 public int num = 10;
 public final int num2 = 20;
 /*
 public final void show() {
 }
 */
}
class Zi extends Fu {
 // Zi中的show()无法覆盖Fu中的show()
 public void show() {
 num = 100;
 System.out.println(num);
 //无法为最终变量num2分配值
 //num2 = 200;
 System.out.println(num2);
 }
}
class FinalDemo {
 public static void main(String[] args) {
 Zi z = new Zi();
 z.show();
 }
}
/*继承的代码体现
 由于继承中方法有一个现象:方法重写。
 所以,父类的功能,就会被子类给覆盖调。
 有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用。
 这个时候,针对这种情况,Java就提供了一个关键字:final
 final:最终的意思。常见的是它可以修饰类,方法,变量。
*/
class Fu {
 public final void show() {
 System.out.println("这里是绝密资源,任何人都不能修改");
 }
}
class Zi extends Fu {
 // Zi中的show()无法覆盖Fu中的show()
 public void show() {
 System.out.println("这是一堆垃圾");
 }
}
class ZiDemo {
 public static void main(String[] args) {
 Zi z = new Zi();
 z.show();
 }
}

(3)面试相关:

A:局部变量

a:基本类型 值不能发生改变

b:引用类型 地址值不能发生改变,但是对象的内容是可以改变的

B:初始化时机

a:只能初始化一次。

b:常见的给值

定义的时候。(推荐)

构造方法中。

/*
 面试题:final修饰局部变量的问题
 基本类型:基本类型的值不能发生改变。
 引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
*/
class Student {
 int age = 10;
}
class FinalTest {
 public static void main(String[] args) {
 //局部变量是基本数据类型
 int x = 10;
 x = 100;
 System.out.println(x);
 final int y = 10;
 //无法为最终变量y分配值
 //y = 100;
 System.out.println(y);
 System.out.println("--------------");
 //局部变量是引用数据类型
 Student s = new Student();
 System.out.println(s.age);
 s.age = 100;
 System.out.println(s.age);
 System.out.println("--------------");
 final Student ss = new Student();
 System.out.println(ss.age);
 ss.age = 100;
 System.out.println(ss.age);
 //重新分配内存空间
 //无法为最终变量ss分配值
 ss = new Student();
 }
}
/*
 final修饰变量的初始化时机
 A:被final修饰的变量只能赋值一次。
 B:在构造方法完毕前。(非静态的常量)
*/
class Demo {
 //int num = 10;
 //final int num2 = 20;
 int num;
 final int num2;
 {
 //num2 = 10;
 }
 public Demo() {
 num = 100;
 //无法为最终变量num2分配值
 num2 = 200;
 }
}
class FinalTest2 {
 public static void main(String[] args) {
 Demo d = new Demo();
 System.out.println(d.num);
 System.out.println(d.num2);
 }
}

2:多态(掌握)

(1)同一个对象在不同时刻体现出来的不同状态。

(2)多态的前提:

A:有继承或者实现关系。

B:有方法重写。

C:有父类或者父接口引用指向子类对象。

多态的分类:

a:具体类多态

class Fu {}

class Zi extends Fu {}

Fu f = new Zi();

b:抽象类多态

abstract class Fu {}

class Zi extends Fu {}

Fu f = new Zi();

c:接口多态

interface Fu {}

class Zi implements Fu {}

Fu f = new Zi();

(3)多态中的成员访问特点

A:成员变量

编译看左边,运行看左边

B:构造方法

子类的构造都会默认访问父类构造

C:成员方法

编译看左边,运行看右边

D:静态方法

编译看左边,运行看左边

为什么?

/*
 多态:同一个对象(事物),在不同时刻体现出来的不同状态。
 举例:
 猫是猫,猫是动物。
 水(液体,固体,气态)。
 多态的前提:
 A:要有继承关系。
 B:要有方法重写。
 其实没有也是可以的,但是如果没有这个就没有意义。
 动物 d = new 猫();
 d.show();
 动物 d = new 狗();
 d.show();
 C:要有父类引用指向子类对象。
 父 f =  new 子();
 用代码体现一下多态。
 多态中的成员访问特点:
 A:成员变量
 编译看左边,运行看左边。
 B:构造方法
 创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
 C:成员方法
 编译看左边,运行看右边。
 D:静态方法
 编译看左边,运行看左边。
 (静态和类相关,算不上重写,所以,访问还是左边的)
 由于成员方法存在方法重写,所以它运行看右边。
*/
class Fu {
 public int num = 100;
 public void show() {
 System.out.println("show Fu");
 }
 public static void function() {
 System.out.println("function Fu");
 }
}
class Zi extends Fu {
 public int num = 1000;
 public int num2 = 200;
 public void show() {
 System.out.println("show Zi");
 }
 public void method() {
 System.out.println("method zi");
 }
 public static void function() {
 System.out.println("function Zi");
 }
}
class DuoTaiDemo {
 public static void main(String[] args) {
 //要有父类引用指向子类对象。
 //父 f =  new 子();
 Fu f = new Zi();
 System.out.println(f.num);
 //找不到符号
 //System.out.println(f.num2);
 f.show();
 //找不到符号
 //f.method();
 f.function();
 }
}

因为成员方法有重写。

(4)多态的好处:

A:提高代码的维护性(继承体现)

B:提高代码的扩展性(多态体现)

/*
 多态的好处:
 A:提高了代码的维护性(继承保证)
 B:提高了代码的扩展性(由多态保证)
 猫狗案例代码
*/
class Animal {
 public void eat(){
 System.out.println("eat");
 }
 public void sleep(){
 System.out.println("sleep");
 }
}
class Dog extends Animal {
 public void eat(){
 System.out.println("狗吃肉");
 }
 public void sleep(){
 System.out.println("狗站着睡觉");
 }
}
class Cat extends Animal {
 public void eat() {
 System.out.println("猫吃鱼");
 }
 public void sleep() {
 System.out.println("猫趴着睡觉");
 }
}
class Pig extends Animal {
 public void eat() {
 System.out.println("猪吃白菜");
 }
 public void sleep() {
 System.out.println("猪侧着睡");
 }
}
//针对动物操作的工具类
class AnimalTool {
 private AnimalTool(){}
 /*
 //调用猫的功能
 public static void useCat(Cat c) {
 c.eat();
 c.sleep();
 }
 //调用狗的功能
 public static void useDog(Dog d) {
 d.eat();
 d.sleep();
 }
 //调用猪的功能
 public static void usePig(Pig p) {
 p.eat();
 p.sleep();
 }
 */
 public static void useAnimal(Animal a) {
 a.eat();
 a.sleep();
 }
}
class DuoTaiDemo2 {
 public static void main(String[] args) {
 //我喜欢猫,就养了一只
 Cat c = new Cat();
 c.eat();
 c.sleep();
 //我很喜欢猫,所以,又养了一只
 Cat c2 = new Cat();
 c2.eat();
 c2.sleep();
 //我特别喜欢猫,又养了一只
 Cat c3 = new Cat();
 c3.eat();
 c3.sleep();
 //...
 System.out.println("--------------");
 //问题来了,我养了很多只猫,每次创建对象是可以接受的
 //但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。
 //我们准备用方法改进
 //调用方式改进版本
 //useCat(c);
 //useCat(c2);
 //useCat(c3);
 //AnimalTool.useCat(c);
 //AnimalTool.useCat(c2);
 //AnimalTool.useCat(c3);
 AnimalTool.useAnimal(c);
 AnimalTool.useAnimal(c2);
 AnimalTool.useAnimal(c3);
 System.out.println("--------------");
 //我喜欢狗
 Dog d = new Dog();
 Dog d2 = new Dog();
 Dog d3 = new Dog();
 //AnimalTool.useDog(d);
 //AnimalTool.useDog(d2);
 //AnimalTool.useDog(d3);
 AnimalTool.useAnimal(d);
 AnimalTool.useAnimal(d2);
 AnimalTool.useAnimal(d3);
 System.out.println("--------------");
 //我喜欢宠物猪
 //定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用
 Pig p = new Pig();
 Pig p2 = new Pig();
 Pig p3 = new Pig();
 //AnimalTool.usePig(p);
 //AnimalTool.usePig(p2);
 //AnimalTool.usePig(p3);
 AnimalTool.useAnimal(p);
 AnimalTool.useAnimal(p2);
 AnimalTool.useAnimal(p3);
 System.out.println("--------------");
 //我喜欢宠物狼,老虎,豹子...
 //定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用
 //前面几个必须写,我是没有意见的
 //但是,工具类每次都改,麻烦不
 //我就想,你能不能不改了
 //太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢?
 //改用另一种解决方案。
 }
 /*
 //调用猫的功能
 public static void useCat(Cat c) {
 c.eat();
 c.sleep();
 }
 //调用狗的功能
 public static void useDog(Dog d) {
 d.eat();
 d.sleep();
 }
 */
}

(5)多态的弊端:

父不能使用子的特有功能。

现象:

子可以当作父使用,父不能当作子使用。

/*
 多态的弊端:
 不能使用子类的特有功能。
*/
class Fu {
 public void show() {
 System.out.println("show fu");
 }
}
class Zi extends Fu {
 public void show() {
 System.out.println("show zi");
 }
 public void method() {
 System.out.println("method zi");
 }
}
class DuoTaiDemo3 {
 public static void main(String[] args) {
 //测试
 Fu f = new Zi();
 f.show();
 f.method();
 }
}/*
 多态的弊端:
 不能使用子类的特有功能。
 我就想使用子类的特有功能?行不行?
 行。
 怎么用呢?
 A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
 B:把父类的引用强制转换为子类的引用。(向下转型)
 对象间的转型问题:
 向上转型:
 Fu f = new Zi();
 向下转型:
 Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。
*/
class Fu {
 public void show() {
 System.out.println("show fu");
 }
}
class Zi extends Fu {
 public void show() {
 System.out.println("show zi");
 }
 public void method() {
 System.out.println("method zi");
 }
}
class DuoTaiDemo4 {
 public static void main(String[] args) {
 //测试
 Fu f = new Zi();
 f.show();
 //f.method();
 //创建子类对象
 //Zi z = new Zi();
 //z.show();
 //z.method();
 //你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢?
 //如果可以,但是如下
 Zi z = (Zi)f;
 z.show();
 z.method();
 }
}

(6)多态中的转型

A:向上转型

从子到父

B:向下转型

从父到子

/*
 ClassCastException:类型转换异常
 一般在多态的向下转型中容易出现
*/
class Animal {
 public void eat(){}
}
class Dog extends Animal {
 public void eat() {}
 public void lookDoor() {
 }
}
class Cat extends Animal {
 public void eat() {
 }
 public void playGame() {
 }
}
class DuoTaiDemo5 {
 public static void main(String[] args) {
 //内存中的是狗
 Animal a = new Dog();
 Dog d = (Dog)a;
 //内存中是猫
 a = new Cat();
 Cat c = (Cat)a;
 //内存中是猫
 Dog dd = (Dog)a; //ClassCastException
 }
}

(7)孔子装爹的案例帮助大家理解多态

多态的问题理解:

 class 孔子爹 {
 public int age = 40;
 public void teach() {
 System.out.println("讲解JavaSE");
 }
 }
 class 孔子 extends 孔子爹 {
 public int age = 20;
 public void teach() {
 System.out.println("讲解论语");
 }
 public void playGame() {
 System.out.println("英雄联盟");
 }
 }
 //Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了
 //但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?
 //然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹
 //向上转型
 孔子爹 k爹 = new 孔子();
 //到人家那里去了
 System.out.println(k爹.age); //40
 k爹.teach(); //讲解论语
 //k爹.playGame(); //这是儿子才能做的
 //讲完了,下班回家了
 //脱下爹的装备,换上自己的装备
 //向下转型
 孔子 k = (孔子) k爹; 
 System.out.println(k.age); //20
 k.teach(); //讲解论语
 k.playGame(); //英雄联盟

(8)多态的练习

A:猫狗案例

B:老师和学生案例

/*   A:
 多态练习:猫狗案例
*/
class Animal {
 public void eat(){
 System.out.println("吃饭");
 }
}
class Dog extends Animal {
 public void eat() {
 System.out.println("狗吃肉");
 }
 public void lookDoor() {
 System.out.println("狗看门");
 }
}
class Cat extends Animal {
 public void eat() {
 System.out.println("猫吃鱼");
 }
 public void playGame() {
 System.out.println("猫捉迷藏");
 }
}
class DuoTaiTest {
 public static void main(String[] args) {
 //定义为狗
 Animal a = new Dog();
 a.eat();
 System.out.println("--------------");
 //还原成狗
 Dog d = (Dog)a;
 d.eat();
 d.lookDoor();
 System.out.println("--------------");
 //变成猫
 a = new Cat();
 a.eat();
 System.out.println("--------------");
 //还原成猫
 Cat c = (Cat)a;
 c.eat();
 c.playGame();
 System.out.println("--------------");
 //演示错误的内容
 //Dog dd = new Animal();
 //Dog ddd = new Cat();
 //ClassCastException
 //Dog dd = (Dog)a;
 }
} 
/* 扩展(1)
 不同地方饮食文化不同的案例
*/
class Person {
 public void eat() {
 System.out.println("吃饭");
 }
}
class SouthPerson extends Person {
 public void eat() {
 System.out.println("炒菜,吃米饭");
 }
 public void jingShang() {
 System.out.println("经商");
 }
}
class NorthPerson extends Person {
 public void eat() {
 System.out.println("炖菜,吃馒头");
 }
 public void yanJiu() {
 System.out.println("研究");
 }
}
class DuoTaiTest2 {
 public static void main(String[] args) {
 //测试
 //南方人
 Person p = new SouthPerson();
 p.eat();
 System.out.println("-------------");
 SouthPerson sp = (SouthPerson)p;
 sp.eat();
 sp.jingShang();
 System.out.println("-------------");
 //北方人
 p = new NorthPerson();
 p.eat();
 System.out.println("-------------");
 NorthPerson np = (NorthPerson)p;
 np.eat();
 np.yanJiu();
 }
}
/*
 看程序写结果:先判断有没有问题,如果没有,写出结果
*/
class Fu {
 public void show() {
 System.out.println("fu show");
 }
}
class Zi extends Fu {
 public void show() {
 System.out.println("zi show");
 }
 public void method() {
 System.out.println("zi method");
 }
}
class DuoTaiTest3 {
 public static void main(String[] args) {
 Fu f = new Zi();
 //找不到符号
 //f.method();
 f.show();
 }
}
/*
 看程序写结果:先判断有没有问题,如果没有,写出结果
 多态的成员访问特点:
 方法:编译看左边,运行看右边。
 继承的时候:
 子类中有和父类中一样的方法,叫重写。
 子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
class A {
 public void show() {
 show2();
 }
 public void show2() {
 System.out.println("我");
 }
}
class B extends A {
 /*
 public void show() {
 show2();
 }
 */
 public void show2() {
 System.out.println("爱");
 }
}
class C extends B {
 public void show() {
 super.show();
 }
 public void show2() {
 System.out.println("你");
 }
}
public class DuoTaiTest4 {
 public static void main(String[] args) {
 A a = new B();
 a.show();
 B b = new C();
 b.show();
 }
}

3:抽象类(掌握)

(1)把多个共性的东西提取到一个类中,这是继承的做法。

但是呢,这多个共性的东西,在有些时候,方法声明一样,但是方法体。

也就是说,方法声明一样,但是每个具体的对象在具体实现的时候内容不一样。

所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。

而一个没有具体的方法体的方法是抽象的方法。

在一个类中如果有抽象方法,该类必须定义为抽象类。

(2)抽象类的特点

A:抽象类和抽象方法必须用关键字abstract修饰

B:抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类

C:抽象类不能实例化

D:抽象类的子类

a:是一个抽象类。

b:是一个具体类。这个类必须重写抽象类中的所有抽象方法。

/*

抽象类的概述:

动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。

我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。

抽象类的特点:

A:抽象类和抽象方法必须用abstract关键字修饰

B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类

C:抽象类不能实例化

因为它不是具体的。

抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?

用于子类访问父类数据的初始化

D:抽象的子类

a:如果不想重写抽象方法,该子类是一个抽象类。

b:重写所有的抽象方法,这个时候子类是一个具体的类。

抽象类的实例化其实是靠具体的子类实现的。是多态的方式。

Animal a = new Cat();

*/

//abstract class Animal //抽象类的声明格式

abstract class Animal {

//抽象方法

//public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体

public abstract void eat();

public Animal(){}

}

//子类是抽象类

abstract class Dog extends Animal {}

//子类是具体类,重写抽象方法

class Cat extends Animal {

public void eat() {

System.out.println("猫吃鱼");

}

}

class AbstractDemo {

public static void main(String[] args) {

//创建对象

//Animal是抽象的; 无法实例化

//Animal a = new Animal();

//通过多态的方式

Animal a = new Cat();

a.eat();

}

}

(3)抽象类的成员特点:

A:成员变量

有变量,有常量

B:构造方法

有构造方法

C:成员方法

有抽象,有非抽象

/*
 抽象类的成员特点:
 成员变量:既可以是变量,也可以是常量。
 构造方法:有。
 用于子类访问父类数据的初始化。
 成员方法:既可以是抽象的,也可以是非抽象的。
 抽象类的成员方法特性:
 A:抽象方法 强制要求子类做的事情。
 B:非抽象方法 子类继承的事情,提高代码复用性。
*/
abstract class Animal {
 public int num = 10;
 public final int num2 = 20;
 public Animal() {}
 public Animal(String name,int age){}
 public abstract void show();
 public void method() {
 System.out.println("method");
 }
}
class Dog extends Animal {
 public void show() {
 System.out.println("show Dog");
 }
}
class AbstractDemo2 {
 public static void main(String[] args) {
 //创建对象
 Animal a = new Dog();
 a.num = 100;
 System.out.println(a.num);
 //a.num2 = 200;
 System.out.println(a.num2);
 System.out.println("--------------");
 a.show();
 a.method();
 }
}