JAVA SE基础《十一》 ---- 面对对象高级二
目录
一、面对对象的三大特征之三:多态
1、认识多态
2、使用多态的好处
3、多态下的类型转换问题
4、多态中调用成员的特点
二、final
1、认识final
2、补充知识:常量详解
三、抽象类
1、认识抽象类
2、使用抽象类的好处
3、抽象类的常见应用场景:模板方法设计模式
四、接口
1、接口概述
2、接口的综合案例
3、接口的其他细节:JDK8开始,接口中新增的三种方法、
4、接口的其他细节:接口的多继承、使用接口的注意事项[了解]
一、面对对象的三大特征之三:多态
1、认识多态
什么是多态?
- 多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
多态的具体代码表现
多态的前提
- 有继承/实现关系;存在父类引用子类对象;存在方法重写。
多态的一个注意事项
多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。
2、使用多态的好处
- 在多态形式下,右边对象是解耦合的,更便于扩展和维护。
- 定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强、更便利。
总结
1、使用多态有什么好处?存在什么问题?
- 可以解耦合,扩展性更强;使用父类类型的变量作为方法的形参时,可以接收一切子类对象。
- 多态下不能直接调用子类的独有方法。
3、多态下的类型转换问题
类型转换
- 自动类型转换:父类 变量名 = new 子类();
- 强制类型转换:子类 变量名 = (子类) 父类变量
强制类型转换的一个注意事项
- 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
- 运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException) 的错误出来。
强转前,Java建议:
- 使用instanceof关键字,判断当前对象的真实类型,再进行强转。
总结
1、类型转换有几种形式?能解决什么问题?
- 自动类型转换、强制类型转换。
- 可以把对象转换成其真正的类型,从而解决了多态下不能调用子类独有方法的问题。
2、强制类型转换需要注意什么?
- 存在继承/实现时,就可以进行强制类型转换,编译阶段不会报错。
- 但是,运行时,如果发现对象的真实类型与强转后的类型不同会报错(ClassCastException)。
3、强制类型转换前?Java建议我们做什么事情?
- 使用instanceof判断当前对象的真实类型:对象 instanceof 类型。
4、多态中调用成员的特点
- 变量调用:编译看左边,运行看左边
- 方法调用:编译看左边,运行看右边
package com.ctgu.pojo; public class Test { public static void main(String[] args) { //创建对象,多态方式 Animal a = new Dog(); // 调用成员变量:编译看左边,运行看左边 ////编译看左边: javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败 // 运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值 System.out.println(a.name); //动物 // 调用成员方法:编译看左边,运行看右边 //编译看左边: javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。 // 运行看右边:java运行代码的时候,实际上运行的是子类中的方法。 a.show(); //Dog----show方法 // 成员变显:在子类的对象中,会把父类约成员变量也继承下的。父: name 子: name // 成员方法;如果子凳对方法进行了重写,那么在虚方法表中是会把父类的方法进行覆盖的。 } } class Animal{ String name = "动物"; public void show(){ System.out.println("Animal----show方法"); } } class Cat extends Animal{ String name = "猫"; public void show(){ System.out.println("Cat----show方法"); } } class Dog extends Animal{ String name = "狗"; public void show(){ System.out.println("Dog----show方法"); } }
二、final
1、认识final
fianl
- final关键字是最终的意思,可以修饰(类、方法、变量)
- 修饰类:该类被称为最终类,特点是不能被继承了。
- 修饰方法:该方法被称为最终方法,特点是不能被重写了。
- 修饰变量:改变量只能被赋值一次。
final修饰变量的注意事项
- final修饰基本类型的变量,变量存储的数据不能被改变。
- final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。
2、补充知识:常量详解
常量
- 使用了static final修饰的成员变量就被称为常量;
- 作用:通常用于记录系统的配置信息。
注意!常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来。
使用常量记录系统配置信息的优势、执行原理
- 代码可读性更好,可维护性也更好。
- 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
三、抽象类
1、认识抽象类
什么是抽象类?
- 在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。
- abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
抽象类的注意事项、特点
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
- 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
- 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写玩抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
总结
1、抽象类、抽象方法是什么样的?
- 都是用abstract修饰的;抽象方法只有方法签名,不能写方法体。
2、抽象类有哪些注意事项和特点?
- 抽象类中可以不写抽象方法,但有抽象方法的类一定是抽象类。
- 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
- 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写玩抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
2、使用抽象类的好处
抽象类的场景和好处
- 父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们设计这样的抽象类,就是为了更好的支持多态。
需求
- 某宠物游戏,需要管理猫、狗的数据。猫的数据有:名字;行为是:喵喵喵的叫~ 。狗的数据有:名字;行为是:汪汪汪的叫~ 。请用面向对象编程设计该程序。
总结
1、抽象类的应用场景和好处是什么?
- 父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态。
3、抽象类的常见应用场景:模板方法设计模式
模板方法设计模式解决了什么问题?
- 解决方法中存在重复代码的问题。
模板方法设计模式的写法
1、定义一个抽象类。
2、在里面定义2个方法
- 一个是模板方法:把相同代码放里面去。
- 一个是抽象方法:具体实现交给子类完成。
多学一招:建议使用final关键字修饰模板方法,为什么?
- 模板方法是给对象直接使用的,不能被子类重写。
- 一旦子类重写了模板方法,模板方法就失效了。
总结
1、模板方法设计模式解决了什么问题?
- 解决方法中存在重复代码的问题。
2、模板方法设计模式应该怎么写?
- 定义一个抽象类。
- 在里面定义2个方法,一个是模板方法:放相同的代码里,一个是抽象方法:具体实现交给子类完成。
3、模板方法建议使用什么关键字修饰?为什么?
- 建议使用final关键字修饰模板方法。
四、接口
1、接口概述
认识接口
- Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口。
- 注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
- 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
接口的好处(重点)
- 弥补了类单继承的不足,一个类同时可以实现多个接口。
- 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。
总结
1、使用接口有啥好处,第一个好处是什么?
- 可以解决类单继承的问题,通过接口,我们可以让一个类有一个亲爹的同时,还可以找多个干爹去扩展自己的功能。
2、为什么我们要通过接口,也就是去找干爹,来扩展自己的功能呢?
- 因为通过接口去找干爹,别人通过你implements的接口,就可以显性的指导你是谁,从而也就可以放心的把你当作谁来用了。
3、使用接口的第二个好处是什么?
- 一个类我们说可以实现多个接口,同样,一个接口也可以被多个类实现的。这样做的好处是我们的程序就可以面向接口编程了,这样我们程序员就可以很方便的灵活切换各种业务实现了。
2、接口的综合案例
此案例分为五个类(一个实体类,两个实现类,一个测试类)和一个接口完成。切换业务只需要更改班级管理类ClassManager的实现接口,把StudentOperatorImpl1改为StudentOperatorImpl2即可。
实体类Student
package com.ctgu.d7_interface_demo; public class Student { private String name; private char sex; private double score; public Student() { } public Student(String name, char sex, double score) { this.name = name; this.sex = sex; this.score = score; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return sex */ public char getSex() { return sex; } /** * 设置 * @param sex */ public void setSex(char sex) { this.sex = sex; } /** * 获取 * @return score */ public double getScore() { return score; } /** * 设置 * @param score */ public void setScore(double score) { this.score = score; } }
班级管理类ClassManager
package com.ctgu.d7_interface_demo; import java.util.ArrayList; public class ClassManager { private ArrayList<Student> students = new ArrayList<>(); private StudentOperator studentOperator = new StudentOperatorImpl1(); public ClassManager(){ students.add(new Student("迪丽热巴",'女',99)); students.add(new Student("古力娜扎",'女',100)); students.add(new Student("马儿扎哈",'男',80)); students.add(new Student("卡尔扎巴",'男',60)); } // 打印全班全部学生的信息 public void printInfo(){ studentOperator.printAllInfo(students); } //打印全班全部学生的平均分 public void printScore(){ studentOperator.printAverageScore(students); } }
接口StudentOperator
package com.ctgu.d7_interface_demo; import java.util.ArrayList; public interface StudentOperator { void printAllInfo(ArrayList<Student> students); void printAverageScore(ArrayList<Student> students); }
方案一实现类StudentOperatorImpl1
package com.ctgu.d7_interface_demo; import java.util.ArrayList; public class StudentOperatorImpl1 implements StudentOperator{ @Override public void printAllInfo(ArrayList<Student> students) { System.out.println("-----------全班全部学生信息如下----------"); for (int i = 0; i < students.size(); i++) { Student s = students.get(i); System.out.println("姓名:" + s.getName() + ",性别:" + s.getSex() + ",成绩:" + s.getScore()); } System.out.println("--------------------------------------"); } @Override public void printAverageScore(ArrayList<Student> students) { double allScore = 0.0; for (int i = 0; i < students.size(); i++) { Student s = students.get(i); allScore += s.getScore(); } System.out.println("平均分:" + (allScore)/students.size()); } }
方案二实现类StudentOperatorImpl2
package com.ctgu.d7_interface_demo; import java.util.ArrayList; public class StudentOperatorImpl2 implements StudentOperator { @Override public void printAllInfo(ArrayList<Student> students) { System.out.println("-----------全班全部学生信息如下----------"); int boy = 0; int girl = 0; for (int i = 0; i < students.size(); i++) { Student s = students.get(i); System.out.println("姓名:" + s.getName() + ",性别:" + s.getSex() + ",成绩:" + s.getScore()); if(s.getSex() == '男'){ boy += 1; }else{ girl += 1; } } System.out.println("男生人数是:" + boy + ",女生人数是:" + girl); System.out.println("班级总人数是:" + students.size()); System.out.println("--------------------------------------"); } @Override public void printAverageScore(ArrayList<Student> students) { double allScore = 0.0; double max = students.get(0).getScore(); double min = students.get(0).getScore(); for (int i = 0; i < students.size(); i++) { Student s = students.get(i); if (s.getScore()>max) max = s.getScore(); if (s.getScore()<min) min = s.getScore(); allScore += s.getScore(); } System.out.println("学生的最高分是" + "max"); System.out.println("学生的最低分是" + "min"); System.out.println("平均分:" + (allScore-min-max) / (students.size()-2)); } }
测试类Test
package com.ctgu.d7_interface_demo; public class Test { public static void main(String[] args) { ClassManager clazz = new ClassManager(); clazz.printInfo(); clazz.printScore(); } }
3、接口的其他细节:JDK8开始,接口中新增的三种方法
JDK8开始,接口新增了三种形式的方法:
JDK8开始,接口中为啥要新增加这些方法?
- 增强了接口的能力,更便于项目的扩展和维护。
总结
1、JDK8开始,接口中新增了哪些方法?
- 默认方法:使用default修饰,使用实现类的对象调用。
- 静态方法:static修饰,必须用当前接名调用
- 私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。
- 他们都会默认被public修饰。
2、JDK8开始,接口中为啥要新增这些方法?
- 增强了接口的能力,更便于项目的扩展和维护。
4、接口的其他细节:接口的多继承、使用接口的注意事项【了解】
接口的多继承
一个接口可以同时继承多个接口
接口多继承的作用
- 便于实现类去实现。
接口其他注意事项(了解)
- 1、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。
- 2、一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
- 3、一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
- 4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
本文作者:小王子C
本文链接:https://www.cnblogs.com/shawncs/p/17666012.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术