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 多态性详解 —— 父类引用子类对象 多态性是 Java 面向对象编程的三个特征之一,另外两个是封装和继承。多态性是指通过方法的重写、重载和动态连接来实现的。在 Java 中,多态性是为了解决单继承问题而引入的...
Java中父类调用子类的方法知识点总结 Java中父类调用子类的方法是面向对象编程中一个常见的问题,了解如何在Java中实现父类调用子类的方法对于编程开发者来说非常重要。本文将通过示例代码和详细的解释,介绍三种...
子类的构造函数可以接受一个父类对象作为参数,然后在构造函数内部,使用成员变量直接赋值或者通过 `base` 关键字调用父类的构造函数。例如: ```csharp public class Parent { public int Id { get; set; } ...
如果一个类继承一个父类,那么子类会拥有父类所规定的所以成员 子类还可以拥有父类没有的独有成员 父类可以完成的任务,子类对象也可以完成 子类可以调用父类Person p= new student(); 声明父类变量,实例化子类...
"黑马程序员Javase笔记"是一个自学者在学习黑马程序员提供的Java全套课程过程中整理的笔记,主要涵盖了Java Standard Edition (Javase) 的核心内容。下面将详细讨论其中的关键知识点。 首先,DOS命令是操作系统中的...
在C#编程语言中,子类继承父类后,可以访问和使用父类中的成员,包括方法和属性。本文将详细讲解如何在C#中实现子类调用父类的方法。 首先,我们要理解继承的基本概念。在C#中,一个类(子类)可以继承另一个类...
3. **变量隐藏**:如果子类和父类有同名的实例变量,子类变量会“隐藏”父类变量。通过父类引用访问这些变量时,实际访问的是父类的变量,而非子类的。 4. **类型转换**:虽然父类引用可以指向子类对象,但反过来...
本文实例讲述了Python实现子类调用父类的方法。分享给大家供大家参考。具体实现方法如下: python和其他面向对象语言类似,每个类可以拥有一个或者多个父类,它们从父类那里继承了属性和方法。如果一个方法在子类的...
当我们创建不同类型的动物对象并调用`showLegs()`方法时,由于多态性的存在,程序会调用相应的子类方法而不是父类的方法。 #### 总结 “父类引用指向子类对象”是面向对象编程中多态性的重要体现之一。它允许我们...
- 子类可以通过构造器调用父类的构造器来初始化父类中的成员变量。这通常是通过使用`super`关键字来完成的。 - **示例**: ```java public Book(String name, int pageCount) { super(name); // 调用Document类的...
总结,Java反射机制为我们提供了强大的动态性,能够方便地获取和操作类的属性和方法,包括私有成员和子类父类中的成员。通过熟练掌握反射技术,开发者可以实现更灵活、更动态的代码,但也需要谨慎使用,以避免潜在的...
5. **调用父类的方法**:在子类中,我们可以使用`super`关键字调用父类的方法。这在需要覆盖父类方法,但又希望在子类中保留原父类行为时非常有用。例如,子类可能有一个重写的方法,但在开始时调用父类的实现: ``...
有时候,我们可能需要在子类中调用父类的方法,这在多态性和代码复用方面非常有用。本篇文章将详细介绍如何在PHP子类中调用父类的方法,并通过一个具体的例子进行演示。 首先,我们需要理解PHP中的`extends`关键字...
《Spring框架2016版深度解析——基于黑马程序员_day2》 在Java开发领域,Spring框架无疑是最为广泛使用的轻量级应用框架之一。2016年,黑马程序员发布的Spring框架教程针对day2部分,深入讲解了该框架的核心概念和...
继承机制允许我们定义一个通用的父类,并让子类继承其属性和方法,从而实现代码复用和提高开发效率。多态性则允许我们在运行时动态地选择要调用的方法,从而提高了程序的灵活性和可扩展性。 在实际开发中,继承机制...
Java 中的 super 关键字有三种用法:在子类的构造函数中调用父类的构造方法、在子类中访问父类的成员变量或方法、在子类的构造函数中直接传递参数给父类的构造方法。 首先,在子类的构造函数中,super 关键字可以...
### 黑马程序员入学Java知识(精华总结) #### 一、Java概述与基础知识 ##### 1、何为编程? 编程是指使用计算机语言来编写指令,这些指令被计算机执行以完成特定任务的过程。通过编程,我们可以控制计算机的行为...
1. **静态成员变量优先于非静态成员变量**:无论是在父类还是子类中,静态成员变量都会在非静态成员变量之前初始化。 2. **继承关系中的初始化顺序**:在继承关系中,父类的成员变量与初始化块会在子类的对应部分...
因为子类中有一个隐藏的引用super会指向父类实例,所以在实例化子类之前会先实例化一个父类,也就是说会先执行父类的构造方法,由于s中包含了父类的实例,所以s可以调用父类的方法。 下面我们来看一下代码:
这是因为子类继承了父类的所有成员变量和成员方法。子类可以通过使用 `super` 关键字来调用父类的方法。 子类重写父类的方法 在 Java 中,子类可以重写父类的方法。这是因为子类需要根据自己的需求来修改父类的...