访问子类对象实例变量
来源:互联网 发布:网络宣传好处 编辑:程序博客网 时间:2024/06/09 16:26
子类的方法可以访问父类的实例变量,这是因为子类继承父类就会获得父类的成员变量和方法;但父类的方法不能访问子类的实例变量,因为父类根本无从知道它将被哪个子类继承.它的子类将会增加怎样的成员变量.
但是,在极端的情况下,可能出现父类访问子类变量的情况.如下所示:
package com.lic.array;public class Demo14 {public static void main(String[] args) {// 创建Drived的构造器创建实例new Drived();}}class Base{// 定义一个名为i的实例变量private int i = 10;public Base(){this.display();}public void display(){System.out.println(i);}}// 继承Base的Drived子类class Drived extends Base{// 定义一个名为i的实例变量private int i = 20;// 构造器,将实例变量i初始化为2000public Drived(){i = 2000;}public void display(){System.out.println(i);}}上面程序的main方法里只有一行代码:new Drived();.这行代码将会调用Drived里的构造器,由于Drived类继承了Base父类,而且Drived构造器里没有显式使用super来调用父类的构造器,因此系统将会自动调用Base类中无参数的构造器来执行初始化.
在Base类的无参数构造器中,只是简单地调用了this.display()方法来输出实例变量i的值,那么这个程序会输出多少呢,10?20?2000?运行该程序,会发现实际输出结果为0.也就是说,实例变量的i的值既不是10,也不是20,更不是2000,而是0,这看上去很奇怪.
接下来将详细介绍这个程序的运行过程,从内存分配的角度来分析程序的输出结果,从而更好地把握程序运行的真实过程.
当程序创建Drived对象时,系统开始为这个Drived对象分配内存空间.需要指出的是,这个Drived对象并不是只有一个i实例变量,它拥有两个i实例变量.
关于一个Java对象怎样拥有多个同名的实例变量,子类定义的成员变量并不能完全覆盖父类中成员变量的知识,后面再进行讲解.
为了解释这个程序,首先需要澄清一个概念:Java对象是由构造器创建的吗?很多书籍,资料中会说,是的.
但实际情况是:构造器只是负责对Java对象实例变量执行初始化(也就是赋初始值),在执行构造器代码之前,该对象所占的内存已经被分配下来,这些内存里值都默认是空值----对于基本类型的变量,默认的空值就是0或false;对于引用类型的变量,默认的空值就是null.
当程序调用new Drived();代码时,系统会先为Derived对象分配内存空间.此时系统内存需要为这个Drived对象分配两块内存,它们分别用于存放Drived对象的两个i实例变量,其中一个属于Base类定义的i实例变量,一个属于Drived类定义的i实例变量,此时这两个i实例变量的值都是0.
接下来程序在执行Drived类的构造器之前,首先会执行Base类的构造器.表面上看,Base类的构造器内只有一行代码this.display();,但由于Base类定义i实例变量时指定了初始值2,因此经过编译器处理后,该构造器应该包含如下两行代码.
i = 2;this.display();因此,程序先将Base类中定义的i实例变量赋值为2,再调用this.display()方法.此处有一个关键:this代表谁?
回答这个问题之前,先进行一些简单的修改,将Base类的构造器改为如下形式:
public Base(){// 直接输出this.i;System.out.println(this.i);this.display();}现在,Base构造器里表面上只有2行代码,实际上应该有3行代码,如下所示:
i = 10;System.out.println(this.i);this.display();再次按运行该程序,将看到输出10,0.看到这样的结果,可能有人会更加混乱了:此时的this到底代表谁?
当this在构造器中时,this代表正在初始化的Java对象.此时的情况是:从源代码来看,此时的this位于Base()构造器内,但这些代码实际放在Drived()构造器内执行----是Drived()构造器隐式调用了Base()构造器的代码.由此可见,此时的this应该是Drived对象,而不是Base对象.
现在问题又出现了,既然this引用代表了Drived对象,那怎么直接输出this.i时会输出10呢?这是因为,这个this虽然代表Drived对象,但它却位于Base构造器中,它的编译时类型Base,而实际引用一个Drived对象.为了证实这一点,再次改写程序.
为Drived类增加一个简单的sub()方法,然后将Base构造器改为如下形式.
public Base(){//直接输出this.iSystem.out.println(this.i);this.display();// 输出this实际的类型,将看到输出DrivedSystem.out.println(this.getClass());// 因为this的编译类型时Base,所以依然不能调用sub()方法//this.sub();}上面程序调用this.getClass()来获取this代表对象的类,将看到输出Drived类,这表明此时this引用代表的是Drived对象.但接下来,程序通过this调用sub()方法时,则无法通过编译,这就是因为this的编译时类型时Base的缘故.
当变量的编译时类型和运行时类型不同时,通过该变量访问它引用的对象的实例变量时,该实例变量的值由声明该变量的类型决定.但通过该变量调用它引用的对象的实例方法时,该方法行为将由它实际所引用的对象来决定.因此,当程序访问this.i时,将会访问Base类中定义的i实例变量,也就是将输出2;但执行this.display();代码时,则实际表现出Drived对象的行为,也就是输出Drived对象的i实例变量,即0.
我们再来把Drived的构造器改一下
public Drived(){this.display();i = 2000;}输出结果又是什么呢?
100class com.lic.array.Drived20这里实际上执行的代码是
int i;public Drived(){ super(); i = 20; this.display(); i = 2000;}结合前面的博文,知道实际执行的代码顺序是先定义实例变量,然后在构造器中按原来的代码顺序初始化赋值.然而super()和this()的调用又是构造器中的第一行代码,执行之前,i的值还是0,所以在Drived父类构造器中调用的display方法会输出0,在Drived的构造器中调用this.display()会输出20.
- 访问子类对象实例变量
- 访问子类对象的实例变量
- 访问子类对象的实例变量
- 访问子类对象的实例变量
- Java 构造器之访问子类对象的实例变量
- Java之访问子类对象的实例变量
- OC中继承子类对象调用方法机制 子类对象访问父类中的实例变量
- OC中继承子类对象调用方法机制 子类对象访问父类中的实例变量
- java 父类访问子类对象的实例变量 继承过程中的执行顺序
- 静态变量、实例变量初始化时机,以及子类隐藏父类成员时,创建子类对象的一些问题
- java一种极端情况下出现父类访问子类的实例变量的情况
- 子类对象实例化全过程
- 子类对象的实例化
- objc直接通过指针访问对象实例变量
- C++接口定义,实现,继承接口类的子类,实例对象访问方法问题
- python父类子类变量访问不一致
- 疯狂java笔记:子类实例变量。
- java中父类变量引用子类对象
- hibernate 管理Session:Session 对象的生命周期与本地线程绑定
- 在Eclipse中进行C/C++开发的配置方法(20140721最新版)
- 叶俊—中国的安东尼·罗宾
- win10 ubuntu16.04 恢复grub引导
- rom添加第三方jar包
- 访问子类对象实例变量
- PHP的json_encode处理中文
- 微信开发专题---1.注册微信平台账号
- Ubuntu16.06 git with socks proxy
- 自旋锁(Ticket,CLH,MCS)
- 索引负面影响测试
- 安鑫 对不起,我们必须辞退你
- ios自学经验
- 关于报错:Attempt to invoke virtual method 'int Android.view.View.getImportantForAccessibility()'