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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 于XINCHENG 中级黑马   /  2013-9-7 09:57  /  2043 人查看  /  18 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 于XINCHENG 于 2013-9-9 03:52 编辑
  1. public class Test01 {
  2.         int a = 1;
  3.         static Test01 testA = new Test01(); // 注意:此处是静态的
  4.         public static void main(String[] args) {
  5.                 // TODO Auto-generated method stub
  6.                 testA.a = 1;
  7. testA.testA.a = 2;
  8.                 System.out.println(testA == testA.testA); // 注意:此处的输出结果为true,为什么?
  9. }
  10. }
复制代码
我被这个问题快搞疯了,求拯救~~~

首先,static Test01 testA = new Test01(); 创建的new Test01()对象是在堆内存还是方法区?
第二,我执行testA.a = 1; 假设是在堆内存中开辟的对象的空间,那么,testA.testA中的第二个testA是方法区中的testA还是堆内存中对象new Test01()的testA?
第三,testA == testA的输出结果为什么是true,我明明创建了两个对象,不应该是true,为什么会这样?

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

18 个回复

倒序浏览
方法区;个类中,一个 static 变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static 变量会共享同一个内存空间

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报 1 1
类属性属于整个类,当系统第一次准备使用这个类时,系统会为该类属性分配内存空间,类属性开始生效,直到该类被卸载,该类的类属性所占的内存才被系统的垃圾回收机制回收。类属性生存范围几乎等同于该类的生存范围。
楼上说的对,类实例中的这个static 变量会共享同一个内存空间。

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
new Test01()对象是在堆内存里;第二个testA是堆内存中对象new Test01()的testA;因为testA.testA指的是当前对象的名为testA的对象,还是同一个对象,即testA,所以,最后的输出结果会是true

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
Bad_Boy 发表于 2013-9-7 10:09
方法区;个类中,一个 static 变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static 变 ...

那请问,static Test01 testA = new Test01(); 的对象是开辟在哪个内存里了?
如果是在方法区中,那里面的int a = 1; 也应该变成static了,和原类Test01中的int a = 1; 不是静态的相矛盾啊
回复 使用道具 举报
Bad_Boy 发表于 2013-9-7 10:09
方法区;个类中,一个 static 变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static 变 ...

我觉得对象应该是在堆内存中的吧?Ps:我是菜鸟,如果说的不对,还请大神多多指教哈!
回复 使用道具 举报
Michael_xpd 发表于 2013-9-7 10:16
new Test01()对象是在堆内存里;第二个testA是堆内存中对象new Test01()的testA;因为testA.testA指的是当前 ...

如果第二个testA是堆内存中的那就说明这个testA不是静态的,和我原对象里面的testA是静态的相矛盾啊
回复 使用道具 举报
于XINCHENG 发表于 2013-9-7 10:20
如果第二个testA是堆内存中的那就说明这个testA不是静态的,和我原对象里面的testA是静态的相矛盾啊
...

对象testA和对象testA.testA是不是同一个对象啊?
回复 使用道具 举报
第一个问题:
    静态方法都是放在方法区中,所以new Test01()对象是在方法区中
第二个问题:
    testA.testA中的第二个testA是方法区中的testA,testA.a = 1这句话只是在堆内存中开辟一个空间存放1这个值
第三个问题:
    整个程序只有 static Test01 testA = new Test01(); 这句话是创建对象。testA.testA.a = 2;这句话相当于testA.a = 2;

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
陶智第 发表于 2013-9-7 10:24
第一个问题:
    静态方法都是放在方法区中,所以new Test01()对象是在方法区中
第二个问题:

static类型的对象被放在共享区,类中的方法区、共享区、数据区都在同一个区;

回复 使用道具 举报
陶智第 发表于 2013-9-7 10:24
第一个问题:
    静态方法都是放在方法区中,所以new Test01()对象是在方法区中
第二个问题:

如果testA在方法区中开辟了对象new Test01()的空间,testA.a = 2; 怎么能又在堆内存中再开辟一次空间,那testA.testA中的第二个testA是哪里来的?
回复 使用道具 举报
于XINCHENG 发表于 2013-9-7 10:17
那请问,static Test01 testA = new Test01(); 的对象是开辟在哪个内存里了?
如果是在方法区中,那里面 ...

这是我理解的

无标题.png (26.17 KB, 下载次数: 8)

应该是这样

应该是这样

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 张聪珉 于 2013-9-7 12:19 编辑

楼主请教,这代码你自己写的?怎么越看越不对劲,对象调用对象自己?我也没看出来哪里有俩对象,我感觉就一个对象testA,就算静态对象可以调用对象自己本身那,返回值还是自身这个对象本身。你理一下思路,有一个对象,是静态的主函数可以直接调用,这个对象是类一加载就已经存在了,new的对象是存在于对内存,某种程度上说这个对象也是只有一个,但是TestA是在方法区或者叫共享数据中,指向了一个对象

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
这代码里你只创建了一个对象,而不管你自己调用自己几次,最终还不是指向内存里的同一个a,那肯定是ture.
回复 使用道具 举报
  1. public class Test01 {
  2.         int a = 1;
  3.         static Test01 testA = new Test01(); //这句话会被编译器分解成两部

  4.       /*

  5.        static Test01 testA;

  6.        static{

  7.               testA=new Test01();

  8.        }

  9.       */
  10.         public static void main(String[] args) {
  11.                 testA.testA.a = 2;
  12.                 // TODO Auto-generated method stub
  13.                 testA.a = 1;
  14.                 System.out.println(testA == testA.testA); // 注意:此处的输出结果为true,为什么?
  15.   }
  16. }
复制代码
静态代码块的特点:随着类的加载而执行,并且只执行一次,优于主函数执行.
testA的类变量在方法区中,引用的是堆内存中的new Test01();
testA.testA.a
关于这句话:testA.testA相当于通过本类对象调用本类的静态成员,特点:被该类的所有对象共享
这个对象A(假设叫A)调用的testA之前已经被初始化(不会再次被初始化,静态成员的初始化是放在静态代码块中,那么也就是说只执行一次)
被初始化的值恰好依然是A...那么我感觉这句话就等价于Test01.testA.a=2;
能力有限,仅供参考.

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
哥们,想知道为什么这样就要知道内存加载的过程。
其实这样的。当主类Test01加载时会先载其静态成员,而加载静态成员分二步,第一是虚拟机本身的静态方法来初始化,把Test01类型的引用变量testA初始化为null。第二步是程序本身对静态变量初始化。这时会生成一个对象,并把地址赋值给引用变量,因为是静态的。所以到此已初始化完毕。以后在也不会在初始化。此时才会加载执行下面代码:
  • testA.a = 1;//访问成员变量a,默认为1
  • testA.testA.a = 2;//这句意思是可理解为静态加载的对象访问静态成员,(实际上最终还是Test01类访问静态变量,这就是关键,testA.testA 相当于Test01.testA  )因为静态只初始化一次。多次访问的是一个地址值,也就是同一个对象。
  • 所以最后对象引用比较为true.同一个对象当然为true,
  • 上面过程明白了,就知道,生成的对象和其引用都只有一个,引用在方法区中。对象一定在堆中,当然也要说明你也可以在搞一个对象。这个是可以的,但不要用
  • testA.testA方式,

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
首先要明确成员变量和局部变量的区别:成员变量就是方法外部,类的内部定义的变量;
局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。
形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。
成员变量存储在堆中的对象里面,由垃圾回收器负责回收。

其中的 a 是成员变量,存放在堆中,所有new出来的对象都存放在堆中。第一个问题
TestA是静态变量,存放在方法区中,它指向Test01.它并没有存放在堆内存中。第二个问题
TestA和TestA.TestA指的都是TestA这个静态变量,它存放的是new Test01的地址,他们比较当然是true了。第三个问题

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

回复 使用道具 举报
楼主你好!


如果您的问题已经解决了,请把您的问题的未解决更改为已解决

谢谢合作!

回复 使用道具 举报
testA == testA.testA
这里比较的是地址值。
而因为testA是static的,所以该类在内存中只有一个testA,也就是说共享该testA。因此地址值是唯一的,拿自己和自己比较,当然true了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马