当前位置: 首页 > news >正文

Java从入门到精通 - 面向对象高级(一)

一、面向对象高级

此笔记参考黑马教程,仅学习使用,如有侵权,联系必删

文章目录

  • 一、面向对象高级
    • 1. static(静态)
      • 1.1 static 修饰成员变量
        • 1.1.1 static
        • 1.1.2 成员变量的执行原理
        • 总结
      • 1.2 static 修饰成员变量的应用场景
        • 类变量的应用场景
        • 案例:
        • 总结
      • 1.3 static 修饰成员方法
        • 1.3.1 成员方法的分类
        • 1.3.2 成员方法的执行原理
        • 代码演示
        • 总结
      • 补充知识:搞懂 mian 方法
      • 1.4 static 修饰成员方法的应用场景
        • 1.4.1 类方法的常见应用场景
        • 1.4.2 工具类是什么?
        • 1.4.3 使用类方法来设计工具类有啥好处?
        • 案例
          • 代码实现
        • 多学一招
        • 总结
      • 1.5 static 的注意事项
        • 代码演示
      • 1.6 static 的应用知识:代码块
        • 1.6.1 代码块概述
        • 代码演示
      • 1.7 static 的应用知识:单例设计模块
        • 1.7.1 什么是设计模式(Design pattern)?
          • 1.7.1.2 单例设计模式(饿汉式单例)
          • 1.7.1.3 单例模式的应用场景和好处
          • 1.7.1.4 单例设计模式的实现方式很多
          • 总结
        • 1.7.2 懒汉式单例设计模式
    • 2. 面向对象三大特征之二:继承
      • 2.1 继承的快速入门
        • 2.1.1 认识继承、特点
          • 2.1.1.1 什么是继承?
          • 2.1.1.2 继承的特点
          • 2.1.1.3 继承的执行原理
          • 代码实现
          • 总结
        • 2.1.2 继承的好处、应用场景
          • 2.1.2.1 使用继承有啥好处?
          • 总结
      • 2.2 继承相关的注意事项
        • 2.2.1 权限修饰符
          • 2.2.1.1 什么是权限修饰符?
          • 2.2.1.2 权限修饰符有几种?各自的作用是什么?
          • 代码演示
        • 2.2.2 单继承、Object 类
          • 2.2.2.1 单继承
          • 2.2.2.2 为何 Java 中的类不支持多继承
          • 2.2.2.3 Object 类
          • 代码演示
          • 总结
        • 2.2.3 方法重写
          • 2.2.3.1 认识方法重写
          • 2.2.3.2 方法重写的应用场景
          • 总结
        • 2.2.4 子类中访问其他成员的特点
        • 2.2.5 子类构造器的特点
          • 2.2.5.1 认识子类构造器的特点
            • 代码演示
          • 2.2.5.1 常见的应用场景
            • 代码演示
          • 补充知识:this(...) 调用兄弟构造器
        • 2.2.6 注意事项小结
    • 3. 面向对象的三大特征之三:多态
      • 3.1 认识多态
        • 3.1.1 什么是多态?
        • 3.1.2 多态的具体代码实现
        • 3.1.3 多态的前提
        • 3.1.4 多态的一个注意事项
        • 代码演示
      • 3.2 使用多态的好处
        • 3.2.1 使用多态的好处
        • 3.2.2 多态下会产生的一个问题,怎么解决?
        • 代码演示
        • 总结
      • 3.3 多态下的类型转换问题
        • 3.3.1 类型转换
        • 3.3.2 强制类型转换的一个注意事项
        • 3.3.3 强转前,Java 建议:
        • 代码演示
        • 总结

1. static(静态)

1.1 static 修饰成员变量

1.1.1 static
  • 叫静态,可以修饰成员变量、成员方法

成员变量按照有无 static 修饰,分为两种:

  • 类变量:有 static 修饰,属于类,在计算机里只有一份,会被类的全部对象共享
  • 实例变量(对象的变量):无 static 修饰,属于每个对象的
public class Student {// 类变量static String name;// 实例变量(对象的变量)int age;
}

![](https://i-blog.csdnimg.cn/direct/97874ce1679f49558b8cae2fc878e5ca.png#pic_center =)

  • 把学生类看成一张学生表,可以创建出学生对象 s1 和 s2,age 没有 static 修饰,所以是对象的变量,也就是每个学生对象中都有一个自己的 age。
  • 而成员变量 name 有 static 修饰,就是类变量,就是说它只属于当前这个类自己持有,不属于对象,也就是说无论我们用这个类创建出了多少个学生对象,这些学生对象中都不会持有这个类变量 name

类变量访问方法

类名.类变量(推荐)
对象.类变量(不推荐)

实例变量访问方法

对象.实例变量
1.1.2 成员变量的执行原理

总结
  1. static 是什么?
  • 叫静态,可以修饰成员变量、成员方法
  1. static 修饰的成员变量叫什么?怎么使用?有啥特点?
  • 类变量(静态成员变量)
类名.类变量(推荐)
对象.类变量(不推荐)
  • 属于类,与类一起加载一次,在内存中只有一份,会被类的所有对象共享
  1. 无 static 修饰的成员变量叫什么?怎么使用?有啥特点?
  • 实例变量(对象变量)
对象.实例变量
  • 属于对象,每个对象中都有一份

1.2 static 修饰成员变量的应用场景

类变量的应用场景
  • 在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住
案例:
  • 系统启动后,要求用户类可以记住自己创建了多少个用户对象了

  • User.java

package Advanced.a_static.d1_staticdemo;public class User {// 类变量public static int number; // public是让它对外完全公开和暴露的public User() {
//        User.number++;// 注意:在同一个类中,访问自己类的类变量,才可以省略类名不写number++;}
}
  • Test2.java
package Advanced.a_static.d1_staticdemo;public class Test2 {public static void main(String[] args) {// 目标:通过案例理解类变量的应用场景User u1 = new User();User u2 = new User();User u3 = new User();User u4 = new User();System.out.println(User.number); // 4}
}
总结
  1. 成员变量有几种?各自在什么情况下定义?
  • 类变量:数据只需要一份,且需要被共享时(访问,修改)
  • 实例变量:每个对象都要有一份,数据各不同(如:name、score、age)
  1. 访问自己类中的类变量,是否可以省略类名不写?
  • 可以的
  • 注意:在某个类中访问其他类里的类变量,必须带类名访问

1.3 static 修饰成员方法

1.3.1 成员方法的分类
  • 类方法:有 static 修饰的成员方法,属于类
public static void printHelloWorld() {System.out.println("Hello World!");System.out.println("Hello World!");
}
类名.类方法(推荐)
对象名.类方法(不推荐)
  • 实例方法:无 static 修饰的成员方法,属于对象
public void printPass() {...
}
对象.实例方法
1.3.2 成员方法的执行原理

![](https://i-blog.csdnimg.cn/direct/259054213b87496fb0edc327c6fbff22.png#pic_center =500)


代码演示
  • Student.java
package Advanced.a_static.d2_static_method;public class Student {double score;// 类方法public static void printHelloWorld() {System.out.println("Hello World!");System.out.println("Hello World!");}// 实例方法(对象的方法)public void printPass() {System.out.println("成绩:" + (score >= 60 ? "及格" : "不及格"));}
}
  • Test.java
package Advanced.a_static.d2_static_method;public class Test {public static void main(String[] args) {// 目标:掌握有无static修饰方法的用法// 1. 类方法的用法// 类名.类方法(推荐)Student.printHelloWorld();// 对象.类方法(不推荐)Student s = new Student();s.printHelloWorld();// 2. 实例方法的用法// 对象.实例方法s.printPass();}
}
总结
  1. static 修饰的成员方法叫什么?如何使用?
  • 类方法(静态方法)
  • 属于类,可以直接用类名访问,也可以用对象访问
类名.类方法(推荐)
对象名.类方法(不推荐)
  1. 无 static 修饰的成员方法叫什么?如何使用?
  • 实例方法(对象的方法)
  • 属于对象,只能用对象访问
对象.实例方法

补充知识:搞懂 mian 方法

public class Test {public static void main(String[] args) {...}
}
  1. main 方法是啥方法?
  • 类方法
    • 因为有 static
  1. main 方法咋就能直接跑起来?
  • 我们用 Java 命令执行这个 Test 程序的时候,虚拟机其实会用这个 Test 类直接去点这个 main 方法来触发这个 main 方法的执行
  • 为什么可以用类名直接去点这个 main 方法执行呢?因为 main 方法也是类方法
  1. 参数 String[] args 是什么?
  • 当我们来执行这个 main 方法的时候实际上我们可以送一些数据给这个参数接收的,这个参数它是一个 String 类型的数组,它可以接一些数据,然后让你这个 main 方法里面的程序来使用这些数据
  1. 怎么在执行 main 方法的时候把数据传给这个参数(String[] args)呢?
  • 在调用 java 命令执行时,直接跟在文件名后面

1.4 static 修饰成员方法的应用场景

1.4.1 类方法的常见应用场景
  • 类方法最常见的应用场景是做工具类
1.4.2 工具类是什么?
  • 工具类中的方法都是一些类方法,每个方法都是用来完成一个功能的,工具类是给开发人员共同使用的
1.4.3 使用类方法来设计工具类有啥好处?
  • 提高了代码复用;调用方便,提高了开发效率
public class XxxxUtil {public static void xxx() {...}public static boolean xxxx(String email) {...}public static String xxxxx(int n) {...}...
}
案例

需求:

  • 某系统的登录界面需要开发并展示四位随机的验证码,系统的注册界面需要开发并展示六位的随机验证码

这两套程序的代码几乎一模一样,存在大量重复代码,这时我们就可以使用类方法设计一个工具类让这两个程序来调用,这样就优化好这个结构了

代码实现
  • MyUtil.java
package Advanced.a_static.d3_util;import java.util.Random;public class MyUtil {private MyUtil() {}public static String createCode(int n) {// 1. 定义2个变量是,一个是记住最终产生的随机验证码,一个是记住可能用到的全部字符String code = "";String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";Random r = new Random();// 2. 开始定义一个循环产生每位随机数字符for (int i = 0; i < 4; i++) {// 3. 随机一个字符范围内的索引int index = r.nextInt(data.length());// 4. 根据索引去全部字符中提取该字符code += data.charAt(index); // code = code + 字符}return code;}
}

  • 为什么工具类中的方法要用类方法,而不是实例方法?

    • 实例方法需要创建对象来调用,此时对象只是为了调用方法,对象占内存,这样会浪费内存
多学一招
  • 工具类没有创建对象的需求,建议将工具类的构造器进行私有
总结
  1. 类方法有啥应用场景?
  • 可以用来设计工具类
  1. 工具类是什么,有什么好处?
  • 工具类中的方法都是类方法,每个类方法都是用来完成一个功能的
  • 提高了代码的复用性;调用方便,提高了开发效率
  1. 为什么工具类要用类方法,而不是实例方法?
  • 实例方法需要创建对象来调用,会浪费内存
  1. 工具类定义时有什么要求?
  • 工具类不需要创建对象,建议将工具类的构造器私有化

1.5 static 的注意事项

  • 类方法中可以直接访问类的成员,不可以直接访问实例成员
  • 实例方法既可以直接访问类成员,也可以直接访问实例成员
  • 实例方法中可以出现 this 关键字,类方法中不可以出现 this 关键字的
代码演示
package Advanced.a_static.d4_static_attention;public class Student {static String schoolName; // 类变量double score; // 实例变量// 1. 类方法中可以直接访问类的成员,不可以直接访问实例成员public static void printHelloWorld() {// 注意:同一个类中,访问类成员可以省略类名不写schoolName = "Feng";Student.printHelloWorld2();//        System.out.println(score); // 会报错
//        printPass(); // 会报错//        System.out.println(this); // 会报错}// 类方法public static void printHelloWorld2() {}// 2. 实例方法中既可以直接访问类成员,也可以直接访问实例成员// 实例方法// 3. 实例方法中可以出现this关键字,类方法中不可以出现this关键字public void printPass() {schoolName = "Feng2";printHelloWorld2();System.out.println(score);printPass2();System.out.println(this); // 哪个对象调用它的实例方法 this就会指向哪个对象}// 实例方法public void printPass2() {}
}

1.6 static 的应用知识:代码块

1.6.1 代码块概述
  • 代码块是类的的5大成分之一(成员变量、构造器、方法、代码块、内部类)

代码块分为两种:

  • 静态代码块:

    • 格式:static {}
    • 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次
    • 作用:完成类的初识化,例如:对类变量的初始化赋值
  • 实例代码块:

    • 格式:{}
    • 特点:每次创建对象时,执行实例代码块,并在构造器前执行
    • 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例对象变量进行初始化赋值
代码演示
  • Student.java
package Advanced.a_static.d5_block;public class Student {static int number = 80;static String schoolName;// 静态代码块static {System.out.println("静态代码块执行了");schoolName = "Feng";}// 实例代码块{System.out.println("实例代码块执行了~~~");System.out.println("有人创建了对象" + this);}public Student() {System.out.println("无参数构造器执行了~~~");}public Student(String name) {System.out.println("有参数构造器执行了~~~");}
}
  • Test.java
package Advanced.a_static.d5_block;public class Test {public static void main(String[] args) {// 目标:认识两种代码块,了解他们的特点和基本作用System.out.println(Student.number); // 静态代码块执行了 80System.out.println(Student.number); // 80System.out.println(Student.number); // 80System.out.println(Student.schoolName); // FengSystem.out.println("-----------------------");Student s1 = new Student(); // 实例代码块执行了~~~ 有人创建了对象Advanced.a_static.d5_block.Student@b4c966a 无参数构造器执行了~~~Student s2 = new Student("张三"); // 实例代码块执行了~~~ 有人创建了对象Advanced.a_static.d5_block.Student@1d81eb93 有参数构造器执行了~~~}
}

1.7 static 的应用知识:单例设计模块

1.7.1 什么是设计模式(Design pattern)?
  • 一个问题通常有 n 种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式
  • 设计模式有20多种,对应20多种软件开发中会遇到的问题
1.7.1.2 单例设计模式(饿汉式单例)
  • 确保一个类只有一个对象

写法

  • 把类的构造器私有
  • 定义一个类变量记住类的一个对象
  • 定义一个类方法,返回对象

代码实现

  • A.java
package Advanced.a_static.d6_singleInstance;public class A {// 2.定义一个类变量记住类的对象private static A a = new A();// 1. 必须私有类的构造器// 使得外面不能创建对象private A() {}// 3. 定义一个类方法返回类的对象public static A getObject() {return a;}
}
  • Test1.java
package Advanced.a_static.d6_singleInstance;public class Test1 {public static void main(String[] args) {// 目标:掌握单例设计模式的写法A a1 = A.getObject();A a2 = A.getObject();System.out.println(a1); // Advanced.a_static.d6_singleInstance.A@b4c966aSystem.out.println(a2); // Advanced.a_static.d6_singleInstance.A@b4c966a}
}
1.7.1.3 单例模式的应用场景和好处
  • Runtime 类
    • 程序的运行环境,Java 程序执行的时候只有一套运行环境,因此 Runtime 它也只需要一个对象就可以代表你那个唯一的运行环境
  • 任务管理器
    • 无论启动多少次任务管理器,其窗口对象始终只有一个
1.7.1.4 单例设计模式的实现方式很多

总结
  1. 什么是设计模式,设计模式主要学什么?单例模式解决了上面问题
  • 设计模式就是具体问题的最优解决方案
  • 解决了什么问题?怎么写?
  • 确保一个类只有一个对象
  1. 单例怎么写?饿汉式单例的特点是什么?
  • 把类的构造器私有;定义一个类变量存储类的一个对象;提供一个类方法返回对象
  • 在获取类对象时,对象已经创建好了
  1. 单例有啥应用场景,有啥好处?
  • 任务管理器对象、获取运行时对象
  • 在这些业务场景下,使用单例模式,可以避免浪费内存

1.7.2 懒汉式单例设计模式
  • 拿对象时,才开始创建对象

写法

  • 把类的构造器私有
  • 定义一个类变量用于存储对象
  • 提供一个类方法,保证返回的是同一个对象

代码实现

  • B.java
package Advanced.a_static.d6_singleInstance;public class B {// 2. 定义一个类变量,用于存储这个类的一个对象private static B b;// 1. 把类的构造器私有private B() {}// 3. 定义一个类方法,这个方法要保证第一次调用时才创建一个对象,后面调用时都会用这同一个对象返回public static B getInstance() {if (b == null) {System.out.println("第一次创建对象~~~");b = new B();}return b;}
}
  • Test2.java
package Advanced.a_static.d6_singleInstance;/*** 目标:掌握懒汉式单例的写法*/public class Test2 {public static void main(String[] args) {B b1 = B.getInstance(); // 第一次拿对象B b2 = B.getInstance();System.out.println(b1 == b2); // true}
}

2. 面向对象三大特征之二:继承

2.1 继承的快速入门

2.1.1 认识继承、特点
2.1.1.1 什么是继承?
  • Java 中提供了一个关键字 extends,用这个关键字,可以让一个类和另一个类建立起父子关系
public class B extends A {}
  • A 类称之为父类(基类或超类)
  • B 类称之为子类(派生类)

2.1.1.2 继承的特点
  • 子类能继承父类的非私有成员(成员变量、成员方法)

继承后对象的创建

  • 子类的对象是由子类、父类共同完成的
2.1.1.3 继承的执行原理

  • 子类对象实际上是由子父类这两张设计图共同创建出来的
代码实现
  • A.java
package Advanced.b_extends.d7_extends;// 父类
public class A {// 公开成员public int i;public void print1() {System.out.println("===print1===");}// 私有成员private int j;private void print2() {System.out.println("===print2===");}
}
  • B.java
package Advanced.b_extends.d7_extends;// 子类
public class B extends A {// 子类是可以继承父类的非私有成员public void print3() {System.out.println(i);print1();//        System.out.println(j); // 报错
//        print2(); // 报错}
}
  • Test.java
package Advanced.b_extends.d7_extends;public class Test {public static void main(String[] args) {// 目标:认识继承、掌握继承的特点B b = new B();System.out.println(b.i); // 0
//        System.out.println(b.j); // 报错b.print1();
//        b.print2(); // 报错b.print3();}
}
总结
  1. 什么是继承?继承后有啥特点?
  • 继承就是用 extends 关键字,让一个类和另一个类建立起一种父子关系
  • 子类可以继承父类非私有的成员
  1. 带继承关系的类,Java 会怎么创建它的对象?对象创建出来后,可以直接访问哪些成员?
  • 带继承关系的类,Java 会用类和其父类,这多张设计图来一起创建类的对象
  • 对象能直接访问什么成员,是由子父类这多张设计图共同决定的,这多张设计图对外暴露了什么成员,对象就可以访问什么成员

2.1.2 继承的好处、应用场景
2.1.2.1 使用继承有啥好处?
  • 减少重复代码的编写

需求:
Feng 的员工管理系统种
需要处理讲师、咨询师的数据
讲师的数据有:姓名、具备的技能
咨询师的数据有:姓名、解答问题的总人数

代码实现

  • People.java
package Advanced.b_extends.d8_extends_application;public class People {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  • Teacher.java
package Advanced.b_extends.d8_extends_application;public class Teacher extends People {private String skill;public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}public void printInfo() {System.out.println(getName() + "具备的技能" + skill);}
}
  • Test.java
package Advanced.b_extends.d8_extends_application;public class Test {public static void main(String[] args) {// 目标:搞清楚继承的好处Teacher t = new Teacher();t.setName("张三");t.setSkill("Java、Spring");System.out.println(t.getName()); // 张三System.out.println(t.getSkill()); // Java、Springt.printInfo(); // 张三具备的技能Java、Spring}
}
总结
  1. 使用继承有啥好处?
  • 减少了重复代码的编写,提高了代码的复用性

2.2 继承相关的注意事项

2.2.1 权限修饰符
2.2.1.1 什么是权限修饰符?
  • 就是用来限制类中的成员(成员变量、成员方法、构造器、代码块…)能够被访问的范围
2.2.1.2 权限修饰符有几种?各自的作用是什么?
修饰符在本类中同一个包下的其他类里任意包下的子类里任意包下的任意类里
private
缺省
protected
public

private < 缺省 < protected < public

代码演示
  • d9_modifer.Fu.java
package Advanced.b_extends.d9_modifer;public class Fu {// 1. 私有:只能在本类中访问private void privateMethod(){System.out.println("===private===");}// 2. 缺省:本类,同一个包下的类void method(){System.out.println("===缺省===");}// 3. protected:本类,同一个包下的类,任意包下的子类protected void protectedMethod(){System.out.println("===protected===");}// 4. public:本类,同一个包下的类,任意包下的子类,任意包下的任意类public void publicMethod(){System.out.println("===public===");}public void test(){privateMethod();method();privateMethod();publicMethod();}
}
  • d9_modifer.Demo.java
package Advanced.b_extends.d9_modifer;public class Demo {public static void main(String[] args) {// 目标:掌握不同权限修饰符的作用Fu f = new Fu();
//        f.privateMethod(); // 报错f.method();f.protectedMethod();f.publicMethod();}
}
  • d10_modifer.Zi.java
package Advanced.b_extends.d10_modifer;import Advanced.b_extends.d9_modifer.Fu;public class Zi extends Fu {public void test() {
//        privateMethod(); // 报错
//        method(); // 报错protectedMethod();publicMethod();}
}
  • d10_modifer.Demo2.java
package Advanced.b_extends.d10_modifer;import Advanced.b_extends.d9_modifer.Fu;public class Demo2 {public static void main(String[] args) {Fu f = new Fu();
//        f.privateMethod(); // 报错
//        f.method(); // 报错
//        f.protectedMethod(); // 报错f.publicMethod();Zi zi = new Zi();
//        zi.protectedMethod(); // 报错}
}

2.2.2 单继承、Object 类
2.2.2.1 单继承

Java 是单继承的,Java 中的类不支持多继承,但是支持多层继承

单继承:指的是一个类只能继承一个直接父类

2.2.2.2 为何 Java 中的类不支持多继承

反证法:

  • 假设 Java 中的类支持多继承,现在有两个类,一个 A 中有一个 method 方法里面打印 “aaa”,一个 B 中有一个 method 方法里面打印 “bbb”
  • 再定义一个 C 类同时继承 A 和 B,那么 C 调用 method 方法时就不知道调用谁的方法了
2.2.2.3 Object 类
  • Object 类是 Java 所有类的祖宗类。我们写的任意一个类,其实都是 Object 的子类或者子孙类
代码演示
package Advanced.b_extends.d11_extends_feature;public class Test {public static void main(String[] args) {// 目标:掌握继承的两个注意事项// 1. Java是单继承的:一个类只能继承一个直接父类;Java中的类不支持多继承,但支持多层继承// 2. Object类是Java中所有类的祖宗A a = new A();B b = new B();}
}class A {
} // extends Object{}class B extends A {
}//class C extends B, A{} // 报错class D extends B {
}
总结
  1. 继承相关的两个注意事项?
  • Java 是单继承的:一个类只能继承一个直接父类;Java 中的类不支持多继承,但是支持多层继承

  • Object 类是 Java 中所有类的祖宗


2.2.3 方法重写
2.2.3.1 认识方法重写

什么是方法重写?

  • 当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写
  • 注意:重写后,方法的访问,Java 会遵循就近原则

方法重写的其他注意事项

  • 重写小技巧:使用 Override 注解,他可以指定 Java 编译器,检查我们方法重写的格式是否正确,代码可读性也会更好
  • 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public > protected > 缺省
  • 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小
  • 私有方法、静态方法不能被重写,如果重写会报错的

代码演示

  • A.java
package Advanced.b_extends.d12_extends_override;public class A {public void print1() {System.out.println("111");}public void print2(int a, int b) {System.out.println("111111");}
}
  • B.java
package Advanced.b_extends.d12_extends_override;public class B extends A {// 方法重写@Override // 安全,可读性好public void print1() {System.out.println("666");}// 方法重写@Overridepublic void print2(int a, int b) {System.out.println("666666");}
}
  • Test.java
package Advanced.b_extends.d12_extends_override;public class Test {public static void main(String[] args) {// 目标:认识方法重写,掌握方法重写的常见应用场景B b = new B();b.print1(); // 666b.print2(2, 3); // 666666}
}
2.2.3.2 方法重写的应用场景
  • 子类重写 Object 类的 toString() 方法,以便返回对象的内容

代码演示

  • Student.java
package Advanced.b_extends.d12_extends_override;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
  • Test.java
package Advanced.b_extends.d12_extends_override;import java.util.ArrayList;public class Test {public static void main(String[] args) {// 目标:认识方法重写,掌握方法重写的常见应用场景B b = new B();b.print1(); // 666b.print2(2, 3); // 666666System.out.println("----------------------------");Student s = new Student("张三", 19);System.out.println(s.toString()); // Advanced.b_extends.d12_extends_override.Student@4e50df2e   Student{name=张三,age=19}System.out.println(s); // Advanced.b_extends.d12_extends_override.Student@4e50df2e   Student{name=张三,age=19}ArrayList list = new ArrayList();list.add("java");System.out.println(list); // [java]   说明ArrayList类中把Object类里面的toString方法进行了重写}
}
总结
  1. 方法重写是什么?
  • 子类写了一个方法名称、形参列表与父类某个方法一样的方法去覆盖父类的该方法
  1. 重写方法有哪些注意事项?
  • 建议加上:@Override 注解,可以校验重写是否正确,同时可读性好
  • 子类重写父类方法时,访问权限必须大于或者等于父类被重写的方法的权限
  • 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小
  • 私有方法、静态方法不能被重写
  1. 方法重写有啥应用场景?
  • 当子类觉得父类的方法不好用,或者不满足自己的需求时,就可以用方法重写

2.2.4 子类中访问其他成员的特点
  1. 在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则
  • 先子类局部范围找
  • 然后子类成员范围找
  • 然后父类成员范围找,如果父类范围还没有找到则报错
  1. 如果父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?
  • 可以通过 super 关键字,指定访问父类的成员:super.父类成员变量/父类成员方法

代码演示

  • F.java
package Advanced.b_extends.d13_extends_visit;public class F {String name = "父类名字";public void print1() {System.out.println("===父类的print1方法执行===");}
}
  • Z.java
package Advanced.b_extends.d13_extends_visit;public class Z extends F {String name = "子类名称";public void showName() {String name = "局部名称";System.out.println(name);System.out.println(this.name);System.out.println(super.name);}@Overridepublic void print1() {System.out.println("===子类的print1方法执行了===");}public void showMethod() {print1(); // 子类的super.print1(); // 父类的}
}
  • Test.java
package Advanced.b_extends.d13_extends_visit;public class Test {public static void main(String[] args) {// 目标:掌握子类中访问其他成员的特点:就近原则Z z = new Z();z.showName(); // 局部名称 子类名称 父类名字z.showMethod(); // ===子类的print1方法执行了=== ===父类的print1方法执行===}
}

2.2.5 子类构造器的特点
2.2.5.1 认识子类构造器的特点

子类构造器的特点:

  • 子类的全部构造器,都会先调用父类的构造器,再执行自己

子类构造器是如何实现调用父类构造器的:

  • 默认情况下,子类全部构造器的第一行代码都是 super(); (写不写都有),它会调用父类的无参数构造器
  • 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写 super(...); ,指定去调用父类的有参数构造器
代码演示
package Advanced.b_extends.d14_extends_constructor;class F {
//    public F() {
//        System.out.println("===父类F的无参数构造器执行了===");
//    }public F(String name, int age) {}
}class Z extends F {public Z() {
//        super(); // 默认存在的super("张三",17);System.out.println("===子类Z的无参数构造器执行了===");}public Z(String name) {
//        super(); // 默认存在的super("张三",17);System.out.println("===子类Z的有参数构造器执行了===");}
}public class Test {public static void main(String[] args) {// 目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景Z z = new Z(); // ===父类F的无参数构造器执行了=== ===子类Z的无参数构造器执行了===Z z2 = new Z("张三"); // ===父类F的无参数构造器执行了=== ===子类Z的有参数构造器执行了===}
}
2.2.5.1 常见的应用场景

搞清楚子类构造器为什么要调用父类的构造器,有啥应用场景?

  • 在继承情况下,由于处理对象数据的构造器拆到了多个类里面去了,所以对象要通过调用这多个构造器才能把对象的数据处理完整

运行过程

  • 子类构造器可以通过父类构造器,把对象中包含父类这部分的数据先初始化赋值,再回来把对象里包含子类这部分的数据也进行初始化赋值
代码演示
package Advanced.b_extends.d14_extends_constructor;public class Test2 {public static void main(String[] args) {// 目标:搞清楚子类构造器为什么要调用父类的构造器,有啥应用场景Teacher t = new Teacher("李四", 36, "Java");System.out.println(t.getName()); // 李四System.out.println(t.getAge()); // 36System.out.println(t.getSkill()); // Java}
}class Teacher extends People {private String skill;public Teacher(String name, int age, String skill) {super(name, age);this.skill = skill;}public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}
}class People {private String name;private int age;public People() {}public People(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
补充知识:this(…) 调用兄弟构造器
  • 任意类的构造器中,是可以通过 this(...) 去调用该类的其他构造器的

this(…) 和 super(…) 使用时的注意事项:

  • this(…)、super(…) 都只能放在构造器的第一行,因此,有了 this(…) 就不能写 super(…) 了,反之亦然

代码演示

package Advanced.b_extends.d14_extends_constructor;public class Test3 {public static void main(String[] args) {// 目标:掌握在类的构造器中,通过this(...)调用兄弟构造器的作用Student s1 = new Student("李四", 26, "家里蹲大学");// 需求:如果学生没有填写学校,那么学校默认就是FengStudent s2 = new Student("张三", 28);System.out.println(s2.getName()); // 张三System.out.println(s2.getAge()); // 28System.out.println(s2.getSchoolName()); // Feng}
}class Student {private String name;private int age;private String schoolName;public Student() {}public Student(String name, int age) {this(name, age, "Feng");}public Student(String name, int age, String schoolName) {this.name = name;this.age = age;this.schoolName = schoolName;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSchoolName() {return schoolName;}public void setSchoolName(String schoolName) {this.schoolName = schoolName;}
}

2.2.6 注意事项小结
  1. 子类构造器有啥特点?
  • 子类中的全部构造器,都必须先调用父类的构造器,再执行自己
  1. super(…) 调用父类有参数构造器的常见场景是什么?
  • 为对象中包含父类这部分的成员变量进行赋值
  1. this(…) 的作用是什么?
  • 在构造器中调用本类的其他构造器
  1. this(…) 和 super(…) 的使用需要注意什么?
  • 都必须放在构造器的第一行

3. 面向对象的三大特征之三:多态

3.1 认识多态

3.1.1 什么是多态?
  • 多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态
3.1.2 多态的具体代码实现
People p1 = new Student();
p1.run();People p2 = new Teacher();
p2.run();
3.1.3 多态的前提
  • 继承/实现关系;存在父类引用子类对象;存在方法重写
3.1.4 多态的一个注意事项
  • 多态是对象、行为的多态,Java 中的属性(成员变量)不谈多态
代码演示
  • People.java
package Advanced.c_polymorphism.d1_polymorphism;// 父类
public class People {public String name = "父类People的名称";public void run() {System.out.println("人可以跑~~~");}
}
  • Student.java
package Advanced.c_polymorphism.d1_polymorphism;public class Student extends People {public String name = "子类Student的名称";@Overridepublic void run() {System.out.println("学生跑得贼快~~~");}
}
  • Teacher.java
package Advanced.c_polymorphism.d1_polymorphism;public class Teacher extends People {public String name = "子类Teacher的名称";@Overridepublic void run() {System.out.println("老师跑的气喘吁吁~~~");}
}
  • Test.java
package Advanced.c_polymorphism.d1_polymorphism;public class Test {public static void main(String[] args) {// 目标:认识多态:对象多态、行为多态// 1. 对象多态People p1 = new Teacher();// 行为多态:识别技巧:编译看左边,运行看右边p1.run(); // 老师跑的气喘吁吁~~~// 注意:对于变量:编译看左边,运行看左边System.out.println(p1.name); // 父类People的名称People p2 = new Student();// 行为多态:识别技巧:编译看左边,运行看右边p2.run(); // 学生跑得贼快~~~System.out.println(p2.name); // 父类People的名称}
}

3.2 使用多态的好处

3.2.1 使用多态的好处
  • 在多态形势下,右边对象是解耦合的,更便于扩展和维护

    • 解耦合:比如说我们在开发系统时,希望把这个系统中的每个模块拆分成一个一个的服务,可以随时的对接,这样更容易扩展和维护,这就是解耦合
  • 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利

3.2.2 多态下会产生的一个问题,怎么解决?
  • 多态下不能使用子类的独有功能
代码演示
  • People.java
package Advanced.c_polymorphism.d2_polymorphism;// 父类
public class People {public String name = "父类People的名称";public void run() {System.out.println("人可以跑~~~");}
}
  • Student.java
package Advanced.c_polymorphism.d2_polymorphism;public class Student extends People {public String name = "子类Student的名称";@Overridepublic void run() {System.out.println("学生跑得贼快~~~");}public void test() {System.out.println("学生需要考试~~~");}
}
  • Teacher.java
package Advanced.c_polymorphism.d2_polymorphism;public class Teacher extends People {public String name = "子类Teacher的名称";@Overridepublic void run() {System.out.println("老师跑的气喘吁吁~~~");}public void test() {System.out.println("老师需要教知识~~~");}
}
  • Test.java
package Advanced.c_polymorphism.d2_polymorphism;public class Test {public static void main(String[] args) {// 目标:理解多态的好处// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随之改变People p1 = new Student();p1.run();
//        p1.test(); // 多态下存在的问题,无法直接调用子类的独有功能Student s = new Student();go(s);Teacher t = new Teacher();go(s);}// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象public static void go(People p) {}
}
总结
  1. 使用多态有什么好处?存在什么问题?
  • 可以解耦合,扩展性更强;使用父类类型的变量作为方法的形参时,可以接收一切子类对象
  • 多态下不能直接调用子类的独有方法

3.3 多态下的类型转换问题

3.3.1 类型转换
  • 自动类型转换:父类 变量名 = new 子类();

    • eg:People p = new Teacher();
  • 强制类型转换:子类 变量名 = (子类) 父类变量

    • eg:Teacher t = (Teacher) p;
3.3.2 强制类型转换的一个注意事项
  • 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
  • 运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来
People p = new Teahcer();Student s = (Student) p; // java.lang.ClassCastException
3.3.3 强转前,Java 建议:
  • 使用 instanceof 关键字,判断当前对象的真实类型,再进行强转
p instanceof Student
代码演示
  • People.java
package Advanced.c_polymorphism.d2_polymorphism;// 父类
public class People {public String name = "父类People的名称";public void run() {System.out.println("人可以跑~~~");}
}
  • Student.java
package Advanced.c_polymorphism.d2_polymorphism;public class Student extends People {public String name = "子类Student的名称";@Overridepublic void run() {System.out.println("学生跑得贼快~~~");}public void test() {System.out.println("学生需要考试~~~");}
}
  • Teacher.java
package Advanced.c_polymorphism.d2_polymorphism;public class Teacher extends People {public String name = "子类Teacher的名称";@Overridepublic void run() {System.out.println("老师跑的气喘吁吁~~~");}public void teach() {System.out.println("老师需要教知识~~~");}
}
  • Test.java
package Advanced.c_polymorphism.d2_polymorphism;public class Test {public static void main(String[] args) {// 目标:理解多态的好处// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随之改变People p1 = new Student();p1.run();
//        p1.test(); // 多态下存在的问题,无法直接调用子类的独有功能// 强制类型转换Student s1 = (Student) p1;s1.test(); // 学生需要考试~~~// 强制类型转换可能存在的问题,编译阶段有继续或者实现关系就可以强制转换,但是运行时可能出现类型转换异常
//        Teacher t1 = (Teacher) p1; // 运行时出现了:ClassCastExceptionif (p1 instanceof Student) {Student s2 = (Student) p1;s2.test(); // 学生需要考试~~~} else {Teacher t2 = (Teacher) p1;t2.teach();}System.out.println("------------------------------");// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象Student s = new Student();go(s); // 学生跑得贼快~~~ 学生需要考试~~~Teacher t = new Teacher();go(t); // 老师跑的气喘吁吁~~~ 老师需要教知识~~~}// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象public static void go(People p) {p.run();if (p instanceof Student) {Student s2 = (Student) p;s2.test();} else if (p instanceof Teacher) {Teacher t2 = (Teacher) p;t2.teach();}}
}
总结
  1. 类型转换有几种形式?能解决什么问题?
  • 自动类型转换、强制类型转换
  • 可以把对象转换成其真正的类型,从而解决了多态下不能调用子类独有方法的问题
  1. 强制类型转换需要注意什么?
  • 存在继承/实现时,就可以进行强制类型转换,编译阶段不会报错
  • 但是,运行时,如果发现对象的真是类型与强转后的类型不同会报错(ClassCastException)
  1. 强制类型转换前,Java 建议我们做什么事情?
  • 使用 instanceof 判断当前对象的真是类型:对象 instanceof 类型

相关文章:

  • HALCON第五讲-> 形状匹配
  • java枚举 注解 异常 常用类
  • Kubernetes安全机制深度解析(一):从身份认证到资源鉴权
  • js将object转换成string
  • Windows桌面图标修复
  • FastDFS 分布式存储系统深度解析与实践指南
  • 关于transceiver复位测试
  • DC3靶机渗透
  • Linux系统详解
  • 网络原理9-HTTP2
  • RAG 技术详解:结合检索与生成的智能问答新范式
  • shell脚本不同执行方式的区别
  • 2025年度重点专项项目申报指南的通知公布!
  • 多线程(4)
  • golang -- map实现原理
  • C++面试(8)-----求链表中环的入口节点
  • 佰力博与你探讨表面电阻测试的一些方法和测试应用场景
  • 树莓派5-ubuntu 24.04 安装 ros环境
  • Oracle OCP认证考试考点详解083系列18
  • 深度学习的分布式训练与集合通信(三)
  • 国内做批发的网站有哪些/app营销策略都有哪些
  • 做b2b外贸有那些网站/东营网站seo
  • 行业网站建设哪家好/sem优化服务公司
  • 商丘企业网站建设公司/推手平台哪个靠谱
  • 有什么网站可以做六级题目嘛/优化推广公司哪家好
  • 广东哪家网站建设/百度seo优化服务