JAVA|面向对象

前言

面向对象(OOP)是基于 "类" 和 "对象" 的编程思想,核心特性为封装、继承、多态,旨在将现实世界的事物抽象为程序中的类和对象,提高代码的复用性和可维护性。

文章目录

    • 前言
    • [1. 类与对象](#1. 类与对象)
      • [1.1 核心概念](#1.1 核心概念)
      • [1.2 创建与使用](#1.2 创建与使用)
      • [1.3 代码示例](#1.3 代码示例)
      • [1.4 内存规则](#1.4 内存规则)
      • 1.5注意事项
    • [2. 方法](#2. 方法)
      • [2.1 方法定义格式](#2.1 方法定义格式)
      • [2.2 方法调用格式](#2.2 方法调用格式)
      • [2.3 方法注意事项](#2.3 方法注意事项)
      • [2.4 方法重载(Overload)](#2.4 方法重载(Overload))
        • [2.4.1 核心定义](#2.4.1 核心定义)
        • [2.4.2 核心作用](#2.4.2 核心作用)
        • [2.4.3 代码示例](#2.4.3 代码示例)
      • [2.5 构造方法](#2.5 构造方法)
        • [2.5.1 核心作用](#2.5.1 核心作用)
        • [2.5.2 核心规则](#2.5.2 核心规则)
        • [2.5.3 代码示例](#2.5.3 代码示例)
    • [3. 封装(三大特性之一)](#3. 封装(三大特性之一))
      • [3.1 核心思想](#3.1 核心思想)
      • [3.2 实现步骤](#3.2 实现步骤)
      • [3.3 标准 JavaBean(实体类规范)](#3.3 标准 JavaBean(实体类规范))
      • [3.4 代码示例](#3.4 代码示例)
      • [3.5 应用场景](#3.5 应用场景)
      • [3.6 注意事项](#3.6 注意事项)
    • [4. 继承(三大特性之二)](#4. 继承(三大特性之二))
      • [4.1 核心概念](#4.1 核心概念)
      • [4.2 语法格式](#4.2 语法格式)
      • [4.3 继承的核心特点](#4.3 继承的核心特点)
      • [4.4 this 与 super 关键字(核心区别)](#4.4 this 与 super 关键字(核心区别))
      • [4.5 代码示例](#4.5 代码示例)
      • [4.5 方法重写(Override,核心重点)](#4.5 方法重写(Override,核心重点))
        • [4.5.1 核心概念](#4.5.1 核心概念)
        • [4.5.2 方法重写的满足条件](#4.5.2 方法重写的满足条件)
        • [4.5.3 代码示例](#4.5.3 代码示例)
      • [4.5.4 构造方法的继承规则](#4.5.4 构造方法的继承规则)
      • [4.5.5 应用场景](#4.5.5 应用场景)
    • [5. 多态(三大特性之三)](#5. 多态(三大特性之三))
      • [5.1 核心概念](#5.1 核心概念)
      • [5.2 多态的前提](#5.2 多态的前提)
      • [5.3 语法格式](#5.3 语法格式)
      • [5.4 代码示例](#5.4 代码示例)
      • [5.5 多态的调用规则](#5.5 多态的调用规则)
      • [5.6 类型转换(多态的核心操作)](#5.6 类型转换(多态的核心操作))
        • [5.6.1 向上转型(自动转换,安全)](#5.6.1 向上转型(自动转换,安全))
        • [5.6.2 向下转型(强制转换,需校验)](#5.6.2 向下转型(强制转换,需校验))
        • [5.6.3 instanceof 关键字](#5.6.3 instanceof 关键字)
      • [5.7 多态的优缺点](#5.7 多态的优缺点)
      • [5.8 应用场景](#5.8 应用场景)

1. 类与对象

1.1 核心概念

  • :对现实世界中一类具有共同属性和行为的事物的抽象描述,是对象的 "模板"。

    • 组成:属性(成员变量)+ 行为(成员方法)。

    • 属性:类中方法外的变量,描述事物的特征(如手机的品牌、价格)。

    • 行为:类中的成员方法(无 static 关键字),描述事物的操作(如手机打电话)。

  • 对象:类的实例化结果,是客观存在的具体实体(如一部具体的手机)。

  • 类与对象的关系:类是抽象描述,对象是具体实例。

1.2 创建与使用

java 复制代码
// 1. 定义类
public class 类名 {
    // 成员变量(属性)
    private 数据类型 变量名;
    
    // 构造方法
    public 类名() {} // 无参构造
    public 类名(参数列表) {} // 带参构造
    
    // 成员方法(行为)
    public 返回值类型 方法名() {
        // 方法体
    }
}

// 2. 创建对象(new关键字必不可少)
类名 对象名 = new 类名(实参);

// 3. 使用对象
对象名.成员变量; // 访问属性
对象名.成员方法(); // 调用方法

1.3 代码示例

java 复制代码
// 1. 定义学生类(模板)
public class Student {
    // 成员属性
    String name;    // 姓名
    String studentId; // 学号
    int age;        // 年龄
    String className; // 班级
    double score;   // 成绩

    // 成员方法(行为)
    // 上课方法
    public void attendClass() {
        System.out.println(name + "(学号:" + studentId + ")在" + className + "班上课,认真听讲");
    }

    // 考试方法
    public void takeExam() {
        System.out.println(name + "参加考试,目前成绩:" + score + "分");
    }

    // 交作业方法
    public void handInHomework() {
        System.out.println(name + "按时交作业,态度认真");
    }

    // 查成绩方法
    public void checkScore() {
        System.out.println(name + "的当前成绩为:" + score + "分");
    }
}

// 2. 测试类(创建对象,调用方法)
public class StudentTest {
    public static void main(String[] args) {
        // 创建对象1:张三
        Student zhangsan = new Student();
        // 给对象赋值(属性初始化)
        zhangsan.name = "张三";
        zhangsan.studentId = "2024001";
        zhangsan.age = 18;
        zhangsan.className = "高一(1)班";
        zhangsan.score = 90.5;
        // 调用对象的方法
        zhangsan.attendClass();
        zhangsan.takeExam();

        System.out.println("-------------------");

        // 创建对象2:李四
        Student lisi = new Student();
        lisi.name = "李四";
        lisi.studentId = "2024002";
        lisi.age = 17;
        lisi.className = "高一(2)班";
        lisi.score = 85.0;
        lisi.attendClass();
        lisi.handInHomework();
    }
}

1.4 内存规则

  • 对象(包括成员变量)存储在 堆内存,堆内存中的对象有默认初始化值(String→null、int→0、double→0.0、boolean→false)。
  • 方法(成员方法、静态方法)存储在 方法区,所有对象共享同一份方法代码,调用时方法入栈执行。
  • 局部变量(方法内的变量)存储在 栈内存,无默认值,必须初始化后才能使用,方法执行完毕后栈内存释放。

1.5注意事项

  • 对象必须通过 new 关键字创建,仅声明引用(如Phone phone = null;)不会创建对象,调用方法会报空指针异常(NullPointerException)。
  • 成员变量与局部变量同名时,方法内优先使用局部变量(就近原则),若要访问成员变量,需用 this.变量名

2. 方法

方法是程序中最小的执行单元,用于封装特定功能,实现代码复用,避免重复编写。

2.1 方法定义格式

  1. 无参无返回值方法(仅执行操作,不返回结果)

    java 复制代码
    // 格式 
    public static void 方法名() { 
    	// 方法体:具体功能代码 
    } 
    
    // 示例:打印欢迎语 
    public static void printWelcome() { 
    	System.out.println("Hello Java!"); 
    }
  2. 带参无返回值方法(接收参数,执行操作,不返回结果)

    java 复制代码
    // 格式 
    public static void 方法名(参数类型1 参数名1, 参数类型2 参数名2) { 
    	// 方法体:使用参数执行操作 
    } 
    
    // 示例:打印指定姓名的欢迎语 
    public static void printWelcome(String name) {
    	System.out.println("Welcome " + name + "!"); 
    }
  3. 带返回值方法(接收参数,执行操作,返回结果给调用者)

    java 复制代码
    // 格式 
    public static 返回值类型 方法名(参数列表) {
    	// 方法体:执行操作 
    	return 结果; // 返回值,类型必须与定义的返回值类型一致 
    } 
    
    // 示例:计算两个整数的和,返回结果 
    public static int add(int a, int b) {
    	int sum = a + b;     
    	return sum; // 返回sum,类型为int,与方法定义一致 
    }

2.2 方法调用格式

方法类型 调用格式 示例
无参无返回值 方法名(); printWelcome();
带参无返回值 方法名(实参1, 实参2); printWelcome("李四");
带返回值 返回值类型 变量名 = 方法名(实参); int sum = add(10, 20);

2.3 方法注意事项

  • 方法不能嵌套定义:方法只能定义在类中,不能定义在另一个方法内部。

    java 复制代码
    // 错误示例 
    public static void method1() {
        // 方法嵌套,编译报错     
        public static void method2() { 
        } 
    }
  • 方法必须先定义,后调用(顺序不能颠倒),除非是递归调用。

  • 调用方法时,实参的数量、类型、顺序必须与形参完全匹配,否则编译报错。

  • void 表示无返回值,可省略 return,也可写 return;(后面不能跟任何数据),否则编译报错。

    java 复制代码
    // 正确示例 
    public static void method() {
    	return; // 无返回值,仅结束方法
    } 
    
    // 错误示例
    public static void method() {
    	return 100; // void方法不能返回数据 
    }
  • 带返回值的方法,所有分支必须有return语句(否则编译报错)。

    java 复制代码
    // 错误示例(缺少else分支的return) 
    public static int getMax(int a, int b) {
        if (a > b) { 
            return a; 
        } 
    } 
    
    // 正确示例 
    public static int getMax(int a, int b) { 
        if (a > b) { 
            return a; 
        } else { 
            return b; 
        } 
    }

2.4 方法重载(Overload)

2.4.1 核心定义

同一类中,方法名相同 ,但 参数列表不同(参数个数不同、参数类型不同、参数顺序不同)的多个方法,与返回值类型、访问修饰符无关。

2.4.2 核心作用

实现"同名不同功",简化调用,例如:add 方法可同时实现两个int求和、两个double求和,无需定义 addIntaddDouble 等不同方法。

2.4.3 代码示例
java 复制代码
// 正确示例
public class OverloadDemo {
    // 重载1:两个int参数
    public static int add(int a, int b) {
        return a + b;
    }

    // 重载2:两个double参数(类型不同)
    public static double add(double a, double b) {
        return a + b;
    }

    // 重载3:三个int参数(个数不同)
    public static int add(int a, int b, int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        System.out.println(add(10, 20));       // 调用重载1
        System.out.println(add(10.5, 20.5));   // 调用重载2
        System.out.println(add(1, 2, 3));      // 调用重载3
    }
}

// 错误示例(不构成重载)
public class OverloadErrorDemo {
    // 错误1:仅返回值不同,不构成重载
    public static int add(int a, int b) { return a + b; }
    public static double add(int a, int b) { return a + b; }

    // 错误2:仅参数名不同,不构成重载
    public static int add(int x, int y) { return x + y; }
}

2.5 构造方法

2.5.1 核心作用

创建对象(new 关键字调用)+ 初始化成员变量,不能用于调用其他功能。

2.5.2 核心规则
  • 方法名与 类名完全一致(大小写也必须一致),无返回值类型(不能写void)。
  • 若未自定义构造方法,JVM会自动生成一个 无参构造方法(默认构造),无方法体。
  • 一旦自定义构造方法(无参/带参),JVM不再提供默认无参构造,若需使用无参构造,需手动编写。
  • 构造方法支持重载(无参构造、带参构造可同时存在)。
  • 构造方法不能手动调用,只能通过 new 类名() 自动调用。
2.5.3 代码示例
java 复制代码
public class Student {
    private String name;
    private int age;

    // 1. 无参构造(手动编写)
    public Student() {
        // 可手动初始化默认值
        this.name = "姓名";
        this.age = 18;
    }

    // 2. 带参构造(重载,初始化时赋值)
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 3. 带参构造(重载,仅初始化姓名)
    public Student(String name) {
        this.name = name;
        this.age = 20;
    }

    public static void main(String[] args) {
        Student s1 = new Student(); // 调用无参构造
        Student s2 = new Student("张三", 18); // 调用带参构造
        Student s3 = new Student("李四"); // 调用重载的带参构造
    }
}

3. 封装(三大特性之一)

3.1 核心思想

隐藏对象的内部实现细节(私有化成员变量),仅对外提供公共的访问方式(get/set方法),控制属性的读写权限,提高代码的安全性、可维护性。

通俗理解:像手机一样,我们不需要知道内部芯片、电路的工作原理,只需通过屏幕、按键(公共接口)操作即可。

3.2 实现步骤

  1. 将类的成员变量用 private 修饰(私有化),禁止外部直接访问。
  2. 为每个私有化成员变量,提供 publicgetXxx() 方法(获取属性值)和 setXxx() 方法(设置属性值)。
  3. setXxx() 方法中添加数据校验逻辑,避免非法值赋值。

3.3 标准 JavaBean(实体类规范)

JavaBean 是封装的典型应用,用于描述实体(如学生、用户、商品),需满足以下4个条件:

  • 类名见名知意(如 Student、User、Goods),采用驼峰命名法(首字母大写,后续单词首字母大写)。
  • 所有成员变量用 private 修饰。
  • 提供无参构造方法(必须有,否则影响框架使用)。
  • 为每个成员变量提供完整的 get/set 方法。

3.4 代码示例

java 复制代码
// 标准JavaBean:Person类(封装实现)
public class Person {
    // 1. 私有化成员变量
    private String name; // 姓名
    private int age;     // 年龄
    private double height; // 身高

    // 2. 无参构造(必须有)
    public Person() {}

    // 3. 带参构造(可选,方便初始化)
    public Person(String name, int age, double height) {
        this.name = name;
        this.setAge(age); // 调用setter,复用校验逻辑
        this.height = height;
    }

    // 4. get/set方法(公共访问接口)
    public String getName() {
        return name; // 获取姓名
    }

    public void setName(String name) {
        this.name = name; // 设置姓名
    }

    public int getAge() {
        return age; // 获取年龄
    }

    public void setAge(int age) {
        // 数据校验:年龄必须在0-150之间,否则赋值默认值18
        if (age < 0 || age > 150) {
            System.out.println("年龄不合法,默认赋值18");
            this.age = 18;
        } else {
            this.age = age;
        }
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    // 行为方法
    public void showInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",身高:" + height + "cm");
    }
}

// 测试类
public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person("王五", 200, 175.5); // 年龄不合法
        p.showInfo(); // 输出:姓名:王五,年龄:18,身高:175.5cm

        p.setAge(25); // 合法年龄
        p.showInfo(); // 输出:姓名:王五,年龄:25,身高:175.5cm

        // 无法直接访问私有属性(编译报错)
        // System.out.println(p.age);
    }
}

3.5 应用场景

  • 所有实体类(JavaBean)的属性私有化,如学生、用户、订单、商品等。
  • 需要控制属性读写权限的场景:如只读属性(仅提供get,不提供set)、只写属性(仅提供set)。
  • 需要对属性赋值进行校验的场景:如年龄、手机号、邮箱格式校验。

3.6 注意事项

  • private 修饰的成员,仅当前类可直接访问,子类、外部类均不能直接访问,只能通过 get/set 访问。
  • get 方法的返回值类型,必须与对应成员变量的类型一致;set 方法的参数类型,必须与对应成员变量的类型一致。

4. 继承(三大特性之二)

4.1 核心概念

子类(派生类)通过 extends 关键字,继承父类(基类)的非私有属性和方法,实现代码复用,建立类之间的层级关系(如"学生"继承"人","猫"继承"动物")。

通俗理解:儿子继承父亲的财产(非私有属性)和技能(非私有方法),同时可以有自己的特有财产和技能。

4.2 语法格式

java 复制代码
// 父类(基类):被继承的类
class 父类名 {
    // 非私有属性和方法
}

// 子类(派生类):继承父类的类
class 子类名 extends 父类名 {
    // 子类特有属性和方法
}

4.3 继承的核心特点

  • Java 仅支持 单继承 :一个子类只能有一个直接父类(避免多继承的歧义),但支持 多层继承(如 A→B→C,C继承B,B继承A)。
  • 所有类默认继承 java.lang.Object 类(根类),若一个类没有显式继承其他类,默认继承 Object。
  • 子类可以继承父类的 非私有成员(非private的成员变量、成员方法),不能继承父类的构造方法。
  • 父类的私有成员(private),子类可以继承 (占用内存),但无法直接访问,需通过父类提供的 public 方法(get/set)访问。
  • 子类可以拥有自己的特有属性和方法,实现功能扩展。

4.4 this 与 super 关键字(核心区别)

关键字 含义 访问成员变量 访问成员方法 访问构造方法
this 当前对象(子类对象) this.变量名(优先访问子类成员) this.方法名()(优先访问子类方法) this()(调用子类自身构造)
super 父类对象 super.变量名(访问父类成员) super.方法名()(访问父类方法) super()(调用父类构造,默认存在)

4.5 代码示例

java 复制代码
// 父类:人类(基类)
public class Person {
    // 非私有成员变量
    protected String name; // protected:子类可直接访问
    private int age;       // private:子类不能直接访问

    // 父类无参构造
    public Person() {
        System.out.println("父类无参构造执行");
    }

    // 父类带参构造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("父类带参构造执行");
    }

    // 父类非私有方法
    public void eat() {
        System.out.println(name + "吃饭");
    }

    // 父类public方法:供子类访问私有成员age
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

// 子类:学生类(继承Person)
public class Student extends Person {
    // 子类特有属性
    private double score; // 成绩

    // 子类无参构造
    public Student() {
        // 默认调用父类无参构造:super();(可省略)
        System.out.println("子类无参构造执行");
    }

    // 子类带参构造
    public Student(String name, int age, double score) {
        super(name, age); // 手动调用父类带参构造(必须在第一行)
        this.score = score;
        System.out.println("子类带参构造执行");
    }

    // 子类特有方法
    public void study() {
        // 访问父类protected成员name(直接访问)
        // 访问父类private成员age(通过getter访问)
        System.out.println(name + "学习,年龄:" + getAge() + ",成绩:" + score);
    }

    // 重写父类方法
    @Override
    public void eat() {
        super.eat(); // 调用父类的eat方法
        System.out.println(name + "在食堂吃饭"); // 子类扩展逻辑
    }

    // get/set(子类特有属性)
    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}

// 测试类
public class ExtendsTest {
    public static void main(String[] args) {
        Student s = new Student("赵六", 20, 95.5);
        s.eat(); // 调用重写后的方法
        s.study(); // 调用子类特有方法
        System.out.println("父类私有age:" + s.getAge()); // 访问父类私有成员
    }
}

4.5 方法重写(Override,核心重点)

4.5.1 核心概念

子类继承父类后,若父类的方法无法满足子类的需求,子类可以定义一个与父类方法名、参数列表、返回值类型完全一致的方法,覆盖父类的方法,称为方法重写。

核心作用:实现"子类个性化",例如"人"的 eat() 方法是"吃饭","学生"的 eat() 方法可以重写为"在食堂吃饭"。

4.5.2 方法重写的满足条件
  • 继承关系(子类继承父类)。
  • 方法名、参数列表、返回值类型完全一致(JDK7+支持协变返回值:子类返回值可以是父类返回值的子类)。
  • 子类方法的访问权限 父类方法的访问权限(如父类是 protected,子类可以是 protected 或 public;父类是 public,子类必须是 public)。
  • 父类方法不能是 private(private方法子类无法继承,无法重写)。
  • 建议添加 @Override 注解(重写校验注解),若不符合重写条件,编译报错,提高代码可读性。
4.5.3 代码示例
java 复制代码
// 父类
public class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }

    protected void run() {
        System.out.println("动物跑步");
    }

    private void sleep() {
        System.out.println("动物睡觉");
    }
}

// 子类
public class Cat extends Animal {
    // 正确重写:满足所有条件
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 正确重写:子类权限 ≥ 父类(protected → public)
    @Override
    public void run() {
        System.out.println("猫快速跑步");
    }

    // 错误示例1:父类方法是private,无法重写(编译报错)
    @Override
    private void sleep() {
        System.out.println("猫睡觉");
    }

    // 错误示例2:参数列表不同,不构成重写(编译报错)
    @Override
    public void eat(String food) {
        System.out.println("猫吃" + food);
    }

    // 错误示例3:访问权限低于父类(public → protected,编译报错)
    @Override
    protected void eat() {
        System.out.println("猫吃鱼");
    }
}

4.5.4 构造方法的继承规则

  • 子类构造方法执行时,第一行默认调用父类无参构造super();),无论是否显式书写,该语句都存在。
  • 若父类没有无参构造(仅自定义了带参构造),子类必须在构造方法的第一行,手动调用父类带参构造super(实参);),否则编译报错。
  • this()(调用子类自身构造)和 super()(调用父类构造),不能同时出现在子类构造方法的第一行,只能二选一。

4.5.5 应用场景

  • 多个类有共同的属性和方法时,提取父类,子类继承父类,减少代码冗余(如学生、老师、管理员,都继承"人"类)。
  • 子类需要修改父类方法的逻辑时,通过方法重写实现个性化(如动物的"叫"方法,猫重写为"喵喵叫",狗重写为"汪汪叫")。

5. 多态(三大特性之三)

5.1 核心概念

多态:同一行为(方法调用),在不同对象上表现出不同的形式。例如:"eat()"方法,猫调用是"吃鱼",狗调用是"吃骨头",本质是方法重写的体现。

5.2 多态的前提

  1. 继承/实现关系(子类继承父类,或实现类实现接口)。
  2. 方法重写(核心,无重写则多态无意义)。
  3. 父类/接口引用指向子类/实现类对象(向上转型,核心格式)。

5.3 语法格式

java 复制代码
// 格式1:父类引用指向子类对象(继承关系)
父类类型 变量名 = new 子类类型();

// 格式2:接口引用指向实现类对象(实现关系)
接口类型 变量名 = new 实现类类型();

5.4 代码示例

java 复制代码
// 父类:动物
public class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }

    public void run() {
        System.out.println("动物跑步");
    }
}

// 子类1:猫
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void run() {
        System.out.println("猫轻盈地跑步");
    }

    // 子类特有方法
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

// 子类2:狗
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    @Override
    public void run() {
        System.out.println("狗快速地跑步");
    }
}

// 测试类
public class PolymorphismTest {
    public static void main(String[] args) {
        // 1. 向上转型(多态核心格式)
        Animal a1 = new Cat(); // 父类引用指向猫对象
        Animal a2 = new Dog(); // 父类引用指向狗对象

        // 2. 多态调用方法:编译看左边,运行看右边
        a1.eat(); // 编译看Animal(有eat方法),运行看Cat → 猫吃鱼
        a1.run(); // 运行看Cat → 猫轻盈地跑步

        a2.eat(); // 运行看Dog → 狗吃骨头
        a2.run(); // 运行看Dog → 狗快速地跑步

        // 3. 多态的弊端:无法直接调用子类特有方法(编译报错)
        // a1.catchMouse(); // 错误:Animal类没有catchMouse方法

        // 4. 解决弊端:向下转型(强制转换)
        if (a1 instanceof Cat) { // 先判断类型,避免转换异常
            Cat c = (Cat) a1; // 强制转换为Cat类型
            c.catchMouse(); // 调用子类特有方法 → 猫抓老鼠
        }

        // 5. JDK14+新特性:instanceof + 强转一步完成(简化代码)
        if (a1 instanceof Cat cat) {
            cat.catchMouse(); // 直接使用cat调用方法
        }
    }
}

5.5 多态的调用规则

  • 成员变量:编译看左边(父类),运行看左边(父类)。

    java 复制代码
    // 示例 
    class Fu {
    	int num = 10; 
    } 
    
    class Zi extends Fu {
    	int num = 20; 
    } 
    
    public class Test {
    	public static void main(String[] args) {
    	Fu f = new Zi();
    	System.out.println(f.num); // 输出10(编译/运行都看左边Fu)
    	} 
    }
  • 成员方法:编译看左边(父类),运行看右边(子类)(核心,因为方法重写)。解释:编译时,JVM检查父类是否有该方法,有则编译通过;运行时,JVM执行子类重写后的方法。

5.6 类型转换(多态的核心操作)

5.6.1 向上转型(自动转换,安全)
  • 格式:子类对象 → 父类引用(父类类型 变量名 = new 子类类型();)。
  • 特点:自动完成,安全(子类是父类的"子集"),但丢失子类特有方法和属性。
  • 本质:多态的核心格式,是向下转型的前提。
5.6.2 向下转型(强制转换,需校验)
  • 格式:父类引用 → 子类对象(子类类型 变量名 = (子类类型) 父类引用;)。
  • 特点:强制完成,不安全(可能引发 ClassCastException 类型转换异常),用于调用子类特有方法。
  • 必须先使用 instanceof 关键字校验类型,确认父类引用指向的是该子类对象,再进行转换。
5.6.3 instanceof 关键字

作用:校验一个对象是否是某个类(或其子类)的实例,返回 boolean 值(true/false),用于避免向下转型异常。

java 复制代码
// 格式
对象名 instanceof 类名/接口名

// 示例(结合向下转型)
Animal a = new Cat();
if (a instanceof Cat) {
    Cat c = (Cat) a; // 安全转换
} else if (a instanceof Dog) {
    Dog d = (Dog) a;
} else {
    System.out.println("无法转换");
}

5.7 多态的优缺点

优点 缺点
提高代码扩展性:父类/接口作为方法参数,可接收所有子类/实现类对象,无需修改方法代码。 无法直接调用子类特有方法和属性,需向下转型。
降低代码耦合度:依赖抽象(父类/接口),不依赖具体实现(子类)。 向下转型可能引发类型转换异常,需用 instanceof 校验。
简化代码调用:统一调用父类方法,不同对象自动执行对应逻 成员变量调用不灵活(始终访问父类变量)。

5.8 应用场景

  • 方法参数统一为父类/接口类型,实现"一个方法接收多种对象"(如定义 feed(Animal a) 方法,可接收 Cat、Dog 等所有动物对象)。
  • 框架开发(如 Spring),通过多态实现解耦,便于扩展(如接口的不同实现类,可切换使用)。
相关推荐
NGC_66112 小时前
插入排序算法
java·数据结构·算法
西门吹-禅2 小时前
【eclipse 升级】
java·ide·eclipse
Seven972 小时前
剑指offer-78、求平⽅根
java
玄〤2 小时前
个人博客网站搭建day6--Spring Boot自定义RedisTemplate配置:优化序列化与Java8时间类型支持
java·spring boot·redis·后端·spring
知我Deja_Vu2 小时前
@Transactional 与 @Transactional(rollbackFor = Exception.class) 的区别详解
java·spring
敲敲千反田2 小时前
CAS和AQS相关问题
java
上海合宙LuatOS2 小时前
LuatOS核心库API——【iotauth 】 IOT 鉴权库
java·单片机·嵌入式硬件·物联网·struts·计算机外设·硬件工程
luod2 小时前
Docker 快速安装Jenkins
java·docker·jenkins
senijusene2 小时前
Linux软件编程: 线程属性与线程间通信详解
java·linux·jvm·算法