A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张文强 中级黑马   /  2012-6-19 15:45  /  2601 人查看  /  12 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 张文强 于 2012-6-19 17:06 编辑

class Game
        {
    int num = 1;
        }
class basketball extends Game
        {
    int num = 5;
        }
public class Test{
    public static void main(String[] args)
    {
        Game p = new basketball();
   
        System.out.println(p.num);
    }
}
//知道打印结果为1,内存中是怎样存在的

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

12 个回复

倒序浏览
在堆内存中有父类对象和子类对象两块内存区域,分别放着各自的num。
回复 使用道具 举报
多态时访问成员变量,无论编译和运行都看左边,Game p = new basketball();System.out.println(p.num);编译的时候看左边Game类里面有没有成员变量num,有的话编译通过,运行的时候也看左边Game类里边有没有成员变量num,有的话就调用Game里的成员变量num,运行通过

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
在堆内存中分别放了Game类和basketball 类的num成员,为什么会在堆内存中?因为是num是成员变量,java将成员变量存放至堆内存,将局部变量存放至栈内存。
另外p.num由于存在多态,在代码编译时会检查父类是否有这个num。而在运行时调用的则是子类的num。

点评

运行时运行的num是父类的,多态中只有非静态方法运行时才是运行子类的!  发表于 2012-6-19 19:01
回复 使用道具 举报
本帖最后由 龙秋地 于 2012-6-19 16:45 编辑
  1. Game p = new basketball();
复制代码
上面这句话在java中叫做向上转型.
表示是将子类的对象赋给了父类引用,或者说是父类引用只想子类对象.
试想一下,虽然你创建出的对象是子类的,但是在虚拟机默认的无参构造方法中
第一行应该super()调用父类,将父类初始化的对象传过来.
在内存中是这样的:
成员变量是在堆里,对象是在栈里一般都是new 出来的.
所以子类对象在栈内存里,而num在堆内存里.
虽然父类的引用p指向了子类对象,但是当你调用的是成员变量的时候,
具体所返回的是栈内存中的num,也就是p自己内部的成员变量.

内存.jpg (35.31 KB, 下载次数: 39)

内存.jpg

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
子类里有一个区域放的父类的实例,子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.(方法片段在内存中只保存有一份,所以不同的实例调用方法时是通过this关键字来区分方法中的属性。)
回复 使用道具 举报
耿鑫 中级黑马 2012-6-19 16:40:37
7#
很简单,当程序执行new BasketBall();会调用BasketBall无参数的构造方法,因为basketball继承了game类,所以会先调用父类的无参数的构造方法,
首先需要澄清一个概念,java对象是由构造器创建的吗?很多书籍,资料中会说是,但实际情况是:构造器只负责对java对象实例变量执行初始化,在执行构造器之前,该对象所占的内存已经被分配下来了,这些内存的值都默认是空值 ------对与基本类型的变量,默认的空值是0或者是false,对于引用类型而言就是null;当执行new BasketBall(); 系统首先会为basketball类分配空间,里边有两块空间分别存放着两个变量num,一个是父类的一个是子类,这个应该知道吧,他们的默认值是0;接下来才是初始化,也就是说上面的程序实际上下可以改写成下面的代码,意思是一样的。
package org.gengxin;

class Game
{
        int num;
       
        public Game()
        {
                num = 1;
        }
}

class basketball extends Game
{
        int num;
       
        public basketball()
        {
                num = 5;
        }
}

public class Test
{
        public static void main(String[] args)
        {
                Game p = new basketball();

                System.out.println(p.num);
        }
}

好的 ,执行完new basketball()之后,内存中就存在两个num, 一个是父类的,一个是子类的,值分别是1和5,再看p指定的类型,Game p显然是父类的类型,所以p.num显然调用的是父类的num。

同理你改成 basketball p = new basketball(); 打印的就是5;

另外提醒下楼主,类命名的时候要遵循驼峰标识规则,你这样看着很不舒服。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
龙秋地 发表于 2012-6-19 16:11
上面这句话在java中叫做向上转型.
表示是将子类的对象赋给了父类引用,或者说是父类引用只想子类对象.
试想 ...

成员变量在堆里边吧。
回复 使用道具 举报
车风波 发表于 2012-6-19 16:41
成员变量在堆里边吧。

{:3_69:}
不好意思写反了,我前后语句都不通了,上面写栈,下面写堆.
回复 使用道具 举报
引用变量有两个类型,编译时类型,运行时类型。当把子类对象赋给父类引用时发生多态。由于对象的属性不具备多态,所以父类引用访问的是父类成员属性。mun 在父类中以存储实例对象的方式存在,子类对象的mun 属性覆盖了父类mun属性,只能通过super 或父类名显示访问。
回复 使用道具 举报
龙秋地 发表于 2012-6-19 16:44
不好意思写反了,我前后语句都不通了,上面写栈,下面写堆.

:handshake
回复 使用道具 举报
张文强 发表于 2012-6-19 17:07

不好意思,刚才又仔细想了一下,发现说成员变量在堆中或者栈中不准确,
因为有成员变量三种情况:
基本数据类型的成员变量,也就是楼主代码中的int num=1,
是在栈中.就是图中左边的部分,我的图是对的,
但是实例成员变量是在堆中.因为是有了对象才有的变量.
回复 使用道具 举报
车风波 发表于 2012-6-19 16:41
成员变量在堆里边吧。

不好意思,刚才又仔细想了一下,发现说成员变量在堆中或者栈中不准确,
因为有成员变量三种情况:
基本数据类型的成员变量,也就是楼主代码中的int num=1,
是在栈中.就是图中左边的部分,我的图是对的,
但是实例成员变量是在堆中.因为是有了对象才有的变量.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马