JAVA 多态(运行时多态和编译时多态)及其内存图解

本文详细探讨了Java中多态的概念,包括对象的多态、多态的好处与弊端,以及多态的前提条件。同时,文章解释了覆盖与隐藏的区别,并讨论了在继承时方法和变量的覆盖与隐藏规则。

定义:某一类事物的多种存在方式(一个对象,两种形态)

对象的多态:父类或者接口的引用指向其子类的对象

多态的好处:

提高了代码的扩展性,前期定义的代码可以使用后期的内容

多态弊端: 前期定义的内容不能使用(调用)后期子类的特有方法(就是多态调用的只能是父类)。但如果是继承子类覆盖了父类方法,多态调用的仍是子类的方法!

多态前提:

1、必须有关系(继承、实现)

2、要有覆盖

多态实际上是自动类型提升:

Animal a = new cat(); ( cat型自动提升为Animal型(向上转型,得按Animal对象进行操作),因此cat只能调用Anima类中的方法,cat中特有功能无法访问 )。如果还想用猫的特有功能,可以强制向下转型:Cat c = (Cat) a。向下转型是为了使用特有方法。如果两者不具备继承关系不能强制转换!(向上转型为了提高扩展性并限制特有方法,向下转型为了使用特定方法)。对于转型自始至终都是子类对象做着类型的变化:

尽管f是指向Zi()这个对象,但是实际运行依然是Zi()这个对象调用方法。因此会先去方法区Zi()这个空间中去找方法。若ZI()方法区中没有则会去找Fu()方法区,再去堆中找相对应的变量。若没有则在往上找,直到Object类。这其实就是运行时多态,即到底运行Fu()的方法还是Zi()的方法等到程序运行时再去确定。对于多态时的成员函数,总的来说分为三种情况:

1父类有方法,子类有覆盖方法:编译通过,执行子类方法。

2父类有方法,子类没覆盖方法:编译通过,执行父类方法(子类继承)。

3父类没方法,子类有方法:编译失败,无法执行。

方法带final、static、private编译时多态因为可以直接确定调用哪个方法。

 

覆盖与隐藏:

以下来自:https://www.cnblogs.com/it12345/p/5221673.html

隐藏 :child隐藏了parent的变量和方法,那么,child不能访问parent被隐藏的变量或者方法,但是,讲B转换成A中,可以访问A被隐藏的变量或者方法

覆盖 :child覆盖了parent的变量或者方法,那么,child不能访问parent被覆盖的变量或者方法,将child转换成parent后同样不能访问parent被覆盖的变量或者方法

 

首先看一下JAVA中方法和变量在继承时的覆盖和隐藏规则

1.父类的实例变量和静态变量能被子类的同名变量隐藏

2.父类的静态方法被子类的同名静态方法隐藏

3.父类的实例方法被子类的同名实例变量覆盖

 

还有几点需要注意的是:

1.不能用子类的静态方法隐藏 父类中同样标示(也就是返回值 名字 参数都一样)的实例方法

2.不能用子类的实例方法覆盖 父类中同样标示的静态方法

3.这点儿请注意,就是变量只会被隐藏 不会被覆盖 ,无论他是实例变量还是静态变量,而且,子类的静态变量可以隐藏 父类的实例变量,子类的实例变量可以隐藏 父类的静态变量

下图结果为3就是因为zi自动转换为Fu类,在zi这个实例的堆内存中找到Fu类num的值。覆盖只发生在函数上!

 

instance of: 

格式:引用  instance of  类/接口

如果给Animal传入了一只狗但是Animal需要转换成猫,这是就会发生错误。因此需要使用instance of来判断传入的引用类型。instanceof 用于判断对象的具体类型,只能应用于引用数据类型判断。一般向下转型时加入instance of判断增强代码健壮性

 

多态成员特点:

 

 

 

 

 

<think>嗯,用户想了解Java多态内存分配机制。首先,我得回忆一下Java内存结构,特别是栈区堆区的作用。栈区存储局部变量方法调用栈帧,而堆区存放对象实例。多态涉及父类引用指向子类对象,所以需要解释内存分配的过程。 根据引用[3],Person worker = new Worker(); 这里父类引用变量指向子类对象。这候,内存里会分配Worker对象的实例,但引用变量worker的类型是Person。这候,成员变量的访问成员方法的调用有什么不同呢?引用[5]提到字段访问由引用类型决定,而方法调用由实际对象类型决定。这可能需要详细说明。 然后,构造器的执行顺序也很重要。引用[2]指出构造器的执行顺序是父类构造器先于子类,而多态方法调用则取决于实际类型。这部分需要分步骤解释,比如分配内存、父类构造、子类构造的顺序。 用户可能还会疑惑多态的好处,比如引用[4]中的问题,直接使用子类引用有什么区别。这里需要强调多态的灵活性扩展性,比如可以用同一父类引用处理不同子类对象,便于代码维护。 另外,内存分配的具体细节,比如子类独有的成员变量是否会被分配,即使通过父类引用访问不到。根据引用[5],堆内存中会包含所有父类子类的成员变量,但引用类型限制了访问范围。这部分需要明确说明。 可能还需要考虑内存图解,帮助用户更直观地理解。例如,栈中的引用变量指向堆中的对象实例,该实例包含父类子类的所有字段,但只能访问父类声明的部分,除非强制类型转换。 最后,要确保回答覆盖了内存分配步骤、字段与方法访问区别、构造顺序,以及多态的优势,同引用相关的资料来支持每个点,确保准确性可信度。</think>### Java多态内存分配机制分步解释 #### 一、内存分配基础结构 1. **栈区(Stack)**:存储方法调用栈帧局部变量(如`Person worker`引用变量)[^1] 2. **堆区(Heap)**:存储实际对象实例(如`new Worker()`创建的实例) 3. **方法区(Method Area)**:存储类信息、静态变量常量池 #### 二、多态内存分配过程(以`Person worker = new Worker();`为例) 1. **对象创建阶段**: - 在堆中分配Worker对象内存块,包含: $$Worker\_Memory = Person\_Fields + Worker\_ExtraFields + Method\_Table$$ - 子类内存包含父类所有字段(包括私有字段)[^5] 2. **引用绑定阶段**: - 栈中创建Person类型引用变量`worker` - 将该引用指向堆中的Worker实例(形成"父类引用指向子类对象")[^3] 3. **构造器执行顺序**: ```mermaid graph TD A[分配内存空间] --> B[初始化父类字段为默认值] B --> C[执行父类构造器] C --> D[初始化子类字段为默认值] D --> E[执行子类构造器] ``` #### 三、访问机制差异 | 访问类型 | 决定因素 | 示例说明 | |----------------|---------------------|------------------------------| | **字段访问** | 引用变量声明类型 | `worker.salary` 编译报错 | | **方法调用** | 实际对象类型 | `worker.work()` 调用子类实现 | | **静态成员** | 引用变量声明类型 | `worker.staticMethod()` | #### 四、内存图解示例 ``` 栈区 堆区 +---------------+ +-------------------------+ | Person worker | --> | Worker对象实例 | | (引用变量) | | - Person字段区 | +---------------+ | - Worker扩展字段区 | | - 方法表指针→Worker方法表 | +-------------------------+ ``` *注:方法表包含实际对象类型的方法地址[^3]* #### 五、多态优势解析 1. **类型统一性**:可通过父类引用操作不同子类对象 2. **扩展性**:新增子类无需修改现有代码(符合开闭原则) 3. **内存效率**:相比接口实现更节省内存(单继承体系)
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值