`
xianglachigen
  • 浏览: 11797 次
社区版块
存档分类
最新评论

黑马程序员——父类调用子类的成员变量 ?挺有意思

 
阅读更多
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
0
0
分享到:
评论
1 楼 newcomes 2012-06-21  
顿时感觉自己知道的太少了

相关推荐

    java多态性详解——父类引用子类对象.pdf

    Java 多态性详解 —— 父类引用子类对象 多态性是 Java 面向对象编程的三个特征之一,另外两个是封装和继承。多态性是指通过方法的重写、重载和动态连接来实现的。在 Java 中,多态性是为了解决单继承问题而引入的...

    Java中父类怎么调用子类的方法

    Java中父类调用子类的方法知识点总结 Java中父类调用子类的方法是面向对象编程中一个常见的问题,了解如何在Java中实现父类调用子类的方法对于编程开发者来说非常重要。本文将通过示例代码和详细的解释,介绍三种...

    子类可以调用父类.pdf

    如果一个类继承一个父类,那么子类会拥有父类所规定的所以成员 子类还可以拥有父类没有的独有成员 父类可以完成的任务,子类对象也可以完成 子类可以调用父类Person p= new student(); 声明父类变量,实例化子类...

    黑马程序员Javase笔记

    "黑马程序员Javase笔记"是一个自学者在学习黑马程序员提供的Java全套课程过程中整理的笔记,主要涵盖了Java Standard Edition (Javase) 的核心内容。下面将详细讨论其中的关键知识点。 首先,DOS命令是操作系统中的...

    Java的子类调用父类的构造方法.pdf

    Java的子类调用父类的构造方法.pdf

    PHP父类调用子类方法的代码例子

    通常情况下,父类的方法在父类本身中被调用,而在某些特定场景下,可能会需要从父类中调用子类中覆盖或者新增的方法。这种做法在面向对象设计中并不常见,因为父类不应该依赖于子类的具体实现,但是了解如何实现这种...

    C#中子类调用父类的实现方法

    在C#编程语言中,子类继承父类后,可以访问和使用父类中的成员,包括方法和属性。本文将详细讲解如何在C#中实现子类调用父类的方法。 首先,我们要理解继承的基本概念。在C#中,一个类(子类)可以继承另一个类...

    黑马程序员Java基础视频辅导班课堂笔记总结Day08

    继承中子父类的成员特点是,成员变量如果子父类中成员变量名不同,直接使用即可,如果变量名相同,局部变量直接用,成员变量用this,父类变量用super。 在继承中,我们可以使用this和super关键字来调用成员变量、...

    c++中子类对象不能调用父类中的虚函数

    然而,这里有一个陷阱:如果通过子类对象直接调用父类的虚函数,编译器会认为是在调用子类自身的实现,即使子类没有覆盖这个虚函数。这就是“子类对象不能调用父类中的虚函数”的含义。例如,假设我们有以下代码: ...

    Python实现子类调用父类的方法

    本文实例讲述了Python实现子类调用父类的方法。分享给大家供大家参考。具体实现方法如下: python和其他面向对象语言类似,每个类可以拥有一个或者多个父类,它们从父类那里继承了属性和方法。如果一个方法在子类的...

    java 子类对象赋值给父类对象的使用

    3. **变量隐藏**:如果子类和父类有同名的实例变量,子类变量会“隐藏”父类变量。通过父类引用访问这些变量时,实际访问的是父类的变量,而非子类的。 4. **类型转换**:虽然父类引用可以指向子类对象,但反过来...

    黑马程序员入学Java精华总结

    ### 黑马程序员入学Java精华总结 #### 一、Java概述与基础知识 1. **何为编程?** - 编程是指通过编写计算机能够理解的指令来解决问题或完成特定任务的过程。这些指令通常被组织成算法,并使用某种编程语言实现。...

    父类引用指向子类对象

    当我们创建不同类型的动物对象并调用`showLegs()`方法时,由于多态性的存在,程序会调用相应的子类方法而不是父类的方法。 #### 总结 “父类引用指向子类对象”是面向对象编程中多态性的重要体现之一。它允许我们...

    黑马程序员基础测试题答案

    1、 编写一个函数,函数内输出一个字符串,并在主函数内调用它。 2、 编写程序计算12+22+32+....+1002的和. 3、 以下代码哪个是正确的?为什么? a. byte b = 1 + 1; b. byte b = 1; b = b + 1; c. byte b = 1;...

    java反射获取所有属性,获取所有get方法,包括子类父类

    总结,Java反射机制为我们提供了强大的动态性,能够方便地获取和操作类的属性和方法,包括私有成员和子类父类中的成员。通过熟练掌握反射技术,开发者可以实现更灵活、更动态的代码,但也需要谨慎使用,以避免潜在的...

    定义一个Document类,包含成员变量name,从Document派生出Book类,增加PageCount变量。编写主函数

    - 子类可以通过构造器调用父类的构造器来初始化父类中的成员变量。这通常是通过使用`super`关键字来完成的。 - **示例**: ```java public Book(String name, int pageCount) { super(name); // 调用Document类的...

    JAVA经典继承与父类调用 geter、seter访问器 构造器

    5. **调用父类的方法**:在子类中,我们可以使用`super`关键字调用父类的方法。这在需要覆盖父类方法,但又希望在子类中保留原父类行为时非常有用。例如,子类可能有一个重写的方法,但在开始时调用父类的实现: ``...

    php实现在子类中调用父类的方法

    有时候,我们可能需要在子类中调用父类的方法,这在多态性和代码复用方面非常有用。本篇文章将详细介绍如何在PHP子类中调用父类的方法,并通过一个具体的例子进行演示。 首先,我们需要理解PHP中的`extends`关键字...

    黑马程序员-SpringCloud-学习笔记-02-微服务拆分及远程调用

    黑马程序员-SpringCloud-学习笔记-02-微服务拆分及远程调用

Global site tag (gtag.js) - Google Analytics