java多态,如何理解父类引用指向子类对象

本文深入解析Java中的多态概念,包括向上转型的意义及其在代码中的应用。通过具体示例阐述了父类引用指向子类对象时的行为特征,以及动态绑定机制如何决定方法调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java多态,如何理解父类引用指向子类对象

要理解多态性,首先要知道什么是“向上转型”。

        我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类。我可以通过   Cat c = new Cat(); 实例化一个Cat的对象,这个不难理解。

        但当我这样定义时:   Animal a = new Cat();  

表示定义了一个Animal类型的引用,指向新建的Cat类型的对象。由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。

     那么这样做有什么意义呢?因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特,   定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。 

    所以,父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,它是无可奈何的;   同时,父类中的一个方法只有在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;   对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接。也可以叫做动态绑定。

     动态绑定是指”在执行期间(而非编译期间)“判断所引用对象的实际类型,根据实际的类型调用其相应的方法。

    看下面这段程序:

class Father {
    public void func1() 

   {
        func2();
    }

 // 这是父类中的func2()方法,因为下面的子类中重写了该方法 ,所以在父类类型的引用中调用时,这个方法将不再有效,取而代之的是将调用子类中重写的func2()方法
    public void func2() {
        System.out.println("AAA");
    }
}
class Child extends Father { // func1(int i)是对func1()方法的一个重载
   由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用
    所以在下面的main方法中child.func1(68)是不对的
    public void func1(int i) {
        System.out.println("BBB");
    } // func2()重写了父类Father中的func2()方法   如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法
    public void func2() {
        System.out.println("CCC");
    }
}
public class PolymorphismTest {
    public static void main(String[] args) {
        Father child = new Child();
        child.func1();// 打印结果将会是什么? } }

         上面的程序是个很典型的多态的例子。子类Child继承了父类Father,并重载了父类的func1()方法,重写了父类的func2()方法。重载后的 func1(int i)和func1()不再是同一个方法,由于父类中没有func1(int i),那么,父类类型的引用child就不能调用func1(int  i)方法。而子类重写了func2()方法,那么父类类型的引用child在调用该方法时将会调用子类中重写的func2()
    }
}

那么该程序将会打印出什么样的结果呢?       很显然,应该是“CCC”。     

    对于多态,可以总结它为:       

     一、使用父类类型的引用指向子类的对象;

    二、该引用只能调用父类中定义的方法和变量;

    三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)

    四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。

多态的3个必要条件:

        1.继承   2.重写   3.父类引用指向子类对象。

### Java 多态的原理及父类引用指向子类对象的工作机制 Java 中的多态是一种重要的面向对象特性,它允许可变数量的不同类型的对象以统一接口的形式呈现出来。以下是关于父类引用指向子类对象工作机制的具体解析。 --- #### 1. **多态的核心概念** 多态指的是在继承关系下,当父类子类拥有相同签名的方法时,运行时会调用实际对象所属类中的方法而非声明类型中的方法[^1]。这种行为依赖于动态绑定(Dynamic Binding),也称为后期绑定或运行时绑定。 - 动态绑定意味着 JVM 在程序运行期间决定应该调用哪个具体实现。 - 只有实例方法支持动态绑定,静态方法和变量则不参与多态[^3]。 --- #### 2. **JVM 的内存模型分析** 为了更好地理解父类引用指向子类对象的行为,可以从 JVM 的内存管理角度出发: ##### (1)**栈区与堆区的作用** - 当创建一个对象时,JVM 在 **堆区** 创建了完整的子类对象,其中包括子类自身的属性、方法以及从父类继承来的所有成员[^3]。 - 同时,在 **栈区** 创建了一个父类类型的引用变量,用来保存堆中对象的地址。 ##### (2)**引用对象的关系** - 栈中的父类引用仅能访问父类定义范围内的方法和字段。 - 若子类重写了父类的方法,则运行时会优先调用子类中的实现。 - 如果尝试访问子类特有的方法或字段,则需显式地将父类引用向下转型为子类类型[^2]。 --- #### 3. **代码示例及其解释** 以下是一个典型的多态场景演示: ```java class Animal { public void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("Dog barks"); } public void wagTail() { System.out.println("Dog wags its tail"); } } public class TestPolymorphism { public static void main(String[] args) { // 父类引用指向子类对象 Animal animal = new Dog(); // 调用了子类重写的 makeSound 方法 animal.makeSound(); // 输出: Dog barks // 尝试调用子类特有方法会报错 // animal.wagTail(); // 编译错误! // 下转型后可访问子类特有方法 ((Dog) animal).wagTail(); // 输出: Dog wags its tail } } ``` - 上述代码展示了父类引用 `animal` 指向子类对象 `Dog`。 - 运行时调用了子类重写的 `makeSound()` 方法[^1]。 - 若要调用子类独有的方法 `wagTail()`,必须先将其强转回子类类型[^2]。 --- #### 4. **方法覆盖 vs 方法隐藏的区别** 需要注意的是,只有非静态方法才能体现多态性,因为它们会被动态绑定到实际对象上。而对于静态方法而言,编译期就已经决定了调用哪一个版本,这被称为方法隐藏而不是覆盖。 举例如下: ```java class Parent { public static void display() { System.out.println("Parent's static method"); } public void test() { System.out.println("Parent's instance method"); } } class Child extends Parent { public static void display() { System.out.println("Child's static method"); } @Override public void test() { System.out.println("Child's instance method"); } } public class StaticVsInstance { public static void main(String[] args) { Parent p = new Child(); p.display(); // 输出: Parent's static method 【静态方法未被覆盖】 p.test(); // 输出: Child's instance method 【动态绑定生效】 Child c = new Child(); c.display(); // 输出: Child's static method 【直接调用本类静态方法】 } } ``` --- #### 5. **总结工作流程** 基于以上讨论,可以归纳出父类引用指向子类对象的工作机制如下: 1. 声明阶段:定义一个父类类型的引用变量。 2. 初始化阶段:让该引用指向一个具体的子类对象实例。 3. 访问控制:通过父类引用只能访问父类可见的部分;若子类重写了某些方法,则运行时会选择子类的实际实现。 4. 特殊需求处理:如需操作子类独占的功能,可通过强制类型转换恢复原始类型[^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值