android培训、
java培训、期待与您交流!
前两天被问到一个程序,觉得挺有意思,拿出来和大家分享一下。程序如下:
class Base
{
private int i = 2;
public Base()
{
this.display();
}
public void display()
{
System.out.println(i);
}
}
class Derived extends Base
{
private int i = 22;
public Derived()
{
i = 222; //②
}
public void display()
{
System.out.println(i);
}
}
public class Test
{
public static void main(String[] args)
{
new Derived(); //①
}
}
问输出的结果是什么?
有些java基础好的人可能一下子就能看出来,我java基础不算牢固,查了一些资料明白了里边的缘故,首先告诉大家结果吧,结果是0,为什么呢?我给大家解释一下。
为了清楚起见我给某些行代码扁了号,首先当程序在①行代码处创建Derived对象时,系统开始为这个Derived对象分配内存空间,需要指出的是,这个Derived对象并不是只有一个i实例变量,它将拥有两个i实例变量。
为了解释这个程序,首先需要澄清一个概念,java对象是由构造器创建的吗?很多书籍,资料中会说是,但实际情况是:构造器只负责对java对象实例变量执行初始化,在执行构造器之前,该对象所占的内存已经被分配下来了,这些内存的值都默认是空值 ------对与基本类型的变量,默认的空值是0或者是false,对于引用类型而言就是null;当程序执行①代码时,系统先为Derived对象分配内存空间,有两块内存空间分别存放Derived对象的两个i实例变量,一个是属于Base的一个是Derived的,此时这两个i实例变量的值都是0;
接下来程序在执行Derived类的构造器之前,首先会执行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();
}
再次运行程序,将看到输出是2和0;看到这个结果,可能有人会更加混乱了,此时的this到底代表谁?
当this在构造器中时,this代表正在初始化的java对象,此时的情况是:从源代码来看,此时的this位于Base()构造器内,但这些代码实际放在Derived()构造器中执行---是Derived构造器隐式调用了Base()构造器的代码,由此可见,此时的this应该是Derived对象,而不是Base对象。现在问题又出现了,既然this引用代表了Derived对象,那怎么直接输出this.i时会输出2呢?这是因为,这个 this虽然代表Derived对象,但它却位于Base构造器中,它的编译时类型是Base,而他/她实际引用了一个Derived对象,为了证实这一点,再次改写程序。
为Derived类增加一个简单的sub()方法,然后将Base构造器改为如下形式。
public Base()
{
System.out.println(this.i);
this.display();
System.out.println(this.getClass());
this.sub();
}
上面程序调用this.getClass()来获取this代表对象的类,将看到输出的是Derived类,这表名此时this引用代表的是 Derived对象,但接下来,程序通过this调用sub方法时,则无法通过编译,这就是因为this的编译时类型是Base的缘故。
当变量的编译时类型和运行时类型不同时,通过该变量访问它所引用的对象的实例变量时,该实例变量的值由声明该变量的类型决定,但通过该变量调用它引用的对象的实例方法时,该方法行为由它实际所引用的对象来决定,一次当程序访问this.i时,它将访问Base类中定义的i实例变量,也就是将输出2;但执行 this.display()时则实际表现出Derived对象的行为,也就是输出Derived对象的i实例变量,即为0;
以上是通过资料查找到的,有问题欢迎指出来。希望对大家有所帮助吧。
----------------------
android培训、
java培训、期待与您交流! ----------------------
详细请查看:
http://edu.csdn.net/heima
分享到:
相关推荐
主要介绍了Java父类调用子类的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
如果一个类继承一个父类,那么子类会拥有父类所规定的所以成员 子类还可以拥有父类没有的独有成员 父类可以完成的任务,子类对象也可以完成 子类可以调用父类Person p= new student(); 声明父类变量,实例化子类...
Java的子类调用父类的构造方法.pdf
今天突然发现需要在父类中调用子类的方法,之前一直都没这么用过,通过实践发现也可以。例子如: 复制代码 代码如下:<?php/** * 父类调用子类方法 基类 * @author LNMP100 * */class BaseApp{ /** * 调用...
本文实例讲述了Python实现子类调用父类的方法。分享给大家供大家参考。具体实现方法如下: python和其他面向对象语言类似,每个类可以拥有一个或者多个父类,它们从父类那里继承了属性和方法。如果一个方法在子类的...
本文实例讲述了C#中实现子类调用父类的方法,分享给大家供大家参考之用。具体方法如下: 一、通过子类无参构造函数创建子类实例 创建父类Person和子类Student。 public class Person { public Person() { ...
调用父类构造函数,对应文件:ClassElement2,文章:https://blog.csdn.net/yysyangyangyangshan/article/details/84311848
黑马程序员安卓教程:Android中服务的调用案例-音乐播放器宣贯.pdf
c++里,指针和引用是很重要的概念,这个程序不仅对指针和引用做了说明、使用,而且对子类不能继承父类虚函数也做了说明。
黑马程序员-SpringCloud-学习笔记-02-微服务拆分及远程调用
1、 编写一个函数,函数内输出一个字符串,并在主函数内调用它。 2、 编写程序计算12+22+32+....+1002的和. 3、 以下代码哪个是正确的?为什么? a. byte b = 1 + 1; b. byte b = 1; b = b + 1; c. byte b = 1;...
2018年黑马程序员全套教程java基础第2天 数据类型转换 算数运算符 比较运算符 逻辑运算符 三元运算符 简单方法定义和调用
子类调用抽象父类,并强制子类重写父类的抽象属性,然后调用父类的方法输出
C++,C 包含类两个类互相调用彼此的类成员变量和方法,里面介绍了如何在头文件中创建相互的类对象,简单易懂
JS在子类中用Object.getPrototypeOf去调用父类方法,是一个很好的js模板
因为子类中有一个隐藏的引用super会指向父类实例,所以在实例化子类之前会先实例化一个父类,也就是说会先执行父类的构造方法,由于s中包含了父类的实例,所以s可以调用父类的方法。 下面我们来看一下代码:
前言在 MFC对话框里利用CHtmlView加载界面(二)———— MFC 调用 JaveScript中,我们实现MFC对JaveScript方法的调用。现在我
构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统...