【Java从入门到大牛】面向对象进阶中篇 快来打我* 2024-04-26 02:45 103阅读 0赞 > ? 本文由 [程序喵正在路上][Link 1] 原创,CSDN首发! > ? 系列专栏:[Java从入门到大牛][Java] > ? 首发时间:2023年7月17日 > ? 欢迎关注?点赞?收藏?留言? > ? 一以贯之的努力 不得懈怠的人生 #### 目录 #### * 面向对象的三大特征之三:多态 * * 认识多态 * 使用多态的好处、类型转换问题 * final * * 认识final * 补充知识:常量详解 * 抽象类 * * 认识抽象类 * 抽象类的常见应用场景:模板方法设计模式 * 接口 * * 接口概述 * 接口的综合案例 * 接口的其他细节:JDK8开始,接口中新增的三种方法 * 接口的其他细节:接口的多继承、使用接口的注意事项 ## 面向对象的三大特征之三:多态 ## ### 认识多态 ### **什么是多态** 多态是在继承 / 实现情况下的一种现象,表现为:对象多态、行为多态 **多态的具体代码体现** People p1 = new Student(); p1.run(); People p2 = new Teacher(); p2.run(); **多态的前提** 有继承 / 实现关系;存在父类引用子类对象;存在方法重写 **多态的注意事项** 多态是对象、行为的多态,Java 中的属性(成员变量)不谈多态 ### 使用多态的好处、类型转换问题 ### **使用多态的好处** * 在多态形式下,右边对象是解耦合的,更便于扩展和维护 * 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利 **多态下会产生的一个问题** 多态下不能使用子类的独有功能 **解决方案:类型转换** * 自动类型转换:`父类 变量名 = new 子类();`,例如:`People p = new Teacher();` * 强制类型转换:`子类 变量名 = (子类)父类变量`,例如:`Teacher t = (Teacher)p;` **强制类型转换的注意事项** * 存在继承 / 实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错 * 运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来 People p = new Teacher(); Student s = (Student)p; // java.lang.ClassCastException **强转前,Java 建议:** * 使用 `instanceof` 关键字,判断当前对象的真实类型,再进行强转 // 格式:对象 instanceof 类型 p instanceof Student ## final ## ### 认识final ### **什么是 final** * final 关键字是最终的意思,可以修饰类、方法或变量 * **修饰类**:该类被称为最终类,特点是不能被继承 * **修饰方法**:该方法被称为最终方法,特点是不能被重写 * **修饰变量**:该变量只能被赋值一次 **final修饰变量的注意事项** * final 修饰基本类型的变量,变量存储的数据不能被改变 * final 修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的 ### 补充知识:常量详解 ### **什么是常量** * 使用了 `static final` 修饰的成员变量就被称为常量 * 作用:通常用于记录系统的配置信息 * 常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来 **使用常量记录系统配置信息的优势和执行原理** * 代码可读性更好,可维护性也会更好 * 程序编译后,常量会被 “宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的 ## 抽象类 ## ### 认识抽象类 ### **什么是抽象类** * 在 Java 中有一个关键字叫:`abstract`,它是抽象的意思,可以用它修饰类或者成员方法 * `abstract` 修饰类,这个类就是抽象列;修饰方法,这个方法就是抽象方法 public abstract class A { // 抽象方法:必须用 abstract 修饰,只有方法签名,不能有方法体 public abstract void test(); } **抽象类的注意事项和特点** * 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类 * 类该有的成员(成员变量、方法、构造器),抽象类都可以有 * 抽象类最主要的特点是:抽象类不能创建对象,仅作为一个特殊的父类,让子类继承并实现 * 一个类继承抽象类,必须重写抽象类的全部抽象方法,否则这个类也必须定义成抽象类 **抽象类的应用场景和好处** 多个类中只要有重复代码(包括相同的方法签名),我们都应该抽取到父类中去,此时,父类中就有可能存在只有方法签名的方法,这时,父类必定是一个抽象类了,我们抽出这样的抽象类,就是为了更好地支持多态 ### 抽象类的常见应用场景:模板方法设计模式 ### **模板方法设计模式解决了什么问题 ?** 解决了方法中存在重复代码的问题 **模板方法设计模式的写法** 1. 定义一个抽象类 2. 在里面定义 2 个方法 * 一个是模板方法:把相同的代码放里面去 * 一个是抽象方法:具体实现交给子类去完成 **多学一招:建议使用 final 关键字修饰模板方法,为什么** * 模板方法是给对象直接使用的,不能被子类重写 * 一旦子类重写了模板方法,模板方法就失效了 **模板方法设计模式的案例** **C.java** // 模板方法设计模式 public abstract class C { // 模板方法 public final void sing() { System.out.println("唱一首你喜欢的歌:"); doSing(); System.out.println("唱完了!"); } // 抽象方法 public abstract void doSing(); } **B.java** public class B extends C { @Override public void doSing() { System.out.println("我们一起学猫叫,一起喵喵喵喵喵~~~"); } } **A.java** public class A extends C { @Override public void doSing() { System.out.println("我是一只小小小小鸟,想要飞就能飞的高~~~"); } } **Test.java** public class Test { public static void main(String[] args) { // 目标:搞清楚模板方法设计模式能解决什么问题,以及怎么写。 B b = new B(); b.sing(); } } ## 接口 ## ### 接口概述 ### **认识接口** Java 提供了一个关键字 `interface`,用这个关键字我们可以定义出一个特殊的结构:接口 public interface 接口名 { // 成员变量(常量) // 成员方法(抽象方法) } 注意:接口不能创建对象,接口是用来被类实现(`implements`)的,实现接口的类称为实现类 修饰符 class 实现类 implements 接口1, 接口2, 接口3, ... { ... } 一个类可以实现多个接口,实现类实现多个接口,必须重写全部接口的全部抽象方法,否则实现类需要定义成抽象类 **接口的好处** * 弥补了类单继承的不足,一个类同时可以实现多个接口 * 让程序可以面向接口编程,这样程序员就可以灵活方便地切换各种业务实现 ### 接口的综合案例 ### **接口的应用案例:班级学生信息管理模块的开发** **需求** 请设计一个班级学生的信息管理模块,学生的数据有:姓名、性别和成绩,功能1:要求打印出全班学生的信息;功能2:要求打印出全班学生的平均成绩 **注意:以上功能的业务实现是有多套方案的,比如:** * 第一套方案:能打印出班级全部学生的信息;能打印班级全部学生的平均分 * 第二套方案:能打印出班级全部学生的信息,包含男女人数;能打印班级全部学生的平均分,要求去掉最高分和最低分后计算平均分 如果系统要求可以支持灵活地切换这些实现方案,我们就必须使用接口 **代码实例** * **学生类 Student.java** 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; } public String getName() { return name; } public void setName(String name) { this.name = name; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } } * **学生操作接口 StudentOperator.java** import java.util.ArrayList; public interface StudentOperator { void printAllInfo(ArrayList<Student> students); void printAverageScore(ArrayList<Student> students); } * **实现类 StudentOperatorImpl.java** import java.util.ArrayList; public class StudentOperatorImpl implements StudentOperator{ @Override public void printAllInfo(ArrayList<Student> students) { System.out.println("----------全班全部学生信息如下--------------"); int count1 = 0; int count2 = 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() == '男'){ count1++; }else { count2++; } } System.out.println("男生人数是:" + count1 + ", 女士人数是:" + count2); 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 - max - min) / (students.size() - 2)); } } * **班级管理类 ClassManager.java** import java.util.ArrayList; public class ClassManager { private ArrayList<Student> students = new ArrayList<>(); private StudentOperator studentOperator = new StudentOperatorImpl(); 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); } } * **测试类 Test.java** public class Test { public static void main(String[] args) { // 目标:完成班级学生信息管理的案例。 ClassManager clazz = new ClassManager(); clazz.printInfo(); clazz.printScore(); } } ### 接口的其他细节:JDK8开始,接口中新增的三种方法 ### **JDK8开始,接口新增了三种形式的方法:** * 默认方法:使用 `default` 修饰,使用实现类的对象调用 * 静态方法:使用 `static` 修饰,必须用当前接口名调用 * 私有方法:使用 `private` 修饰,JDK9 开始才有的,只能在接口内部被就调用 * 它们都会默认被 `public` 修饰 **为什么要新增这些方法** 增强了接口的能力,更便于项目的扩展和维护 ### 接口的其他细节:接口的多继承、使用接口的注意事项 ### **接口的多继承** 一个接口可以同时继承多个接口 public interface C extends A, B { } **接口多继承的作用** 便于实现类去实现 **接口的其他注意事项(了解)** * 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承 * 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现 * 一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的 * 一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可 [Link 1]: https://blog.csdn.net/weixin_62511863?spm=1011.2421.3001.5343 [Java]: https://blog.csdn.net/weixin_62511863/category_12365679.html?spm=1001.2014.3001.5482
相关 php 面向对象进阶,面向对象进阶 面向对象高级语法部分 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里 柔情只为你懂/ 2023年01月16日 06:54/ 0 赞/ 244 阅读
相关 面向对象进阶 isinstance和issubclass isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): 雨点打透心脏的1/2处/ 2021年11月10日 21:36/ 0 赞/ 366 阅读
还没有评论,来说两句吧...