解决方案 »

  1.   

    亲,不要太纠结~  哈哈  我说说我的理解:首先,你说的A实例中, 所有的变量名:a、b、c、s 包括后面的s2 都是在栈空间中的,它就是你说的一个指针,指向堆空间中的对象。其次,就要弄起字符串的特殊之处了,字符串的话,他的创建,不光是在堆空间中创建一块区域,它还会在字符串池中创建一个对象。 然后由栈空间的指针指向他们。
      

  2.   

    所以A实例中s是分配到栈空间的,而他的值"abc"是在堆空间和字符串池的。同理  字符串s2的值"bcd"是被分配在堆区和字符串池了。。
      

  3.   

    1、主函数中,当执行A a=new A()时,我们知道,a相当于指针,被分配在栈中;new A()才是真正的对象,被分配在堆中。那么,a实例中的引用类型成员变量a和b此时如何分配内存的,分配在哪?指针和实例都在堆中吗?
    对象在堆里,基础变量在栈里另外,a实例中的字符串成员变量s是被分配在内存的哪个区域?常量区还是堆区?
    这个字符串是预赋值的,相当于常量,在常量池,也就是方法区里
    2、当执行a.f2()语句时,字符串s2的值"bcd"是被分配在堆区,还是常量池?
    但凡你在代码里看到的="string"这种类型的东西,全部都在常量池里
      

  4.   

    首先了解一下对象的内存布局,(以HotSpot虚拟机为例子)主要分为:
    1.对象头,主要是对象自己运行时数据(包括hashCode、gc分代年龄、线程持有的锁、锁状态标识等等)和对象的类型;
    2.实例数据,是对象真正有效数据;
    3.对齐填充,用于占位符;
    ===============================================================================================1、主函数中,当执行A a=new A()时,我们知道,a相当于指针,被分配在栈中;new A()才是真正的对象,
         被分配在堆中。那么,a实例中的引用类型成员变量a和b此时如何分配内存的,分配在哪?指针和实例都在堆中吗?
         另外,a实例中的字符串成员变量s是被分配在内存的哪个区域?常量区还是堆区?答:
    1.a实例中怎么会出现名称相同的字段(a和b)?
    2.a实例的a和b.无是基本类型还是引用类型都在堆中,只是他们指向的值或对象可能是堆中也可能在常量池中;
    3.成员变量s也是在堆,s指向的常量池中的常量"bcd"的地址
    =============================================================
    2、当执行a.f2()语句时,字符串s2的值"bcd"是被分配在堆区,还是常量池?
    答:"bcd"是在常量池中,而s2是在栈中;
      

  5.   

    java把内存分两种:一种是栈内存,另一种是堆内存
     (1)在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;
     (2)堆内存用来存放由new创建的对象和数组以及对象的实例变量。
      

  6.   

    兄弟,你的最后一句话有问题的。
    经过我自己的研究,“bcd”应该是被分配在了常量池中,不再分配到堆中。
      

  7.   

    兄弟,你的最后一句话有问题的。
    经过我自己的研究,“bcd”应该是被分配在了常量池中,不再分配到堆中。恩恩,你自己有理解就好,不一定我的就是对的,我只是说说我的理解
      

  8.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
      

  9.   


    兄弟,我的疑问跟上面的回答一样。我知道字符串s的值是被分配在常量池中,请你看清楚,我是问的,s这个符号引用(从c++的角度看就是指针)本身是被分配在了哪里?堆还是栈?
      

  10.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
    sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时
      

  11.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
    sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?
      

  12.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
    sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。
      

  13.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
    sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。我的类型定义错了,里面包含了重名的a和b,一个是int型的,一个是复合类型的。假设把复合类型的a和b的名字改成e和f,修改后如下:
    class A{
            int a,b;
            A e,f;
            //......
    }
    则修改后,当执行new A()时,是不是要在堆中分配4×6=64个字节的内存空间了?
      

  14.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
    sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。我的类型定义错了,里面包含了重名的a和b,一个是int型的,一个是复合类型的。假设把复合类型的a和b的名字改成e和f,修改后如下:
    class A{
            int a,b;
            A e,f;
            //......
    }
    则修改后,当执行new A()时,是不是要在堆中分配4×6=64个字节的内存空间了?
    -_-#...果然是搞c++的,我不太记得int占多少空间了,总之创建A的时候会给A分配内存,这块内存里包含了ab两个int的长度,和两个指针ef(你可以这样理解),由于ef没有被初始化,实际上是指向null的
      

  15.   


    还是这位大神的回答非常精准,看出了问题的本质。
    其实我看了一些书之后,也认为应该是这样分配的。只是网上绝大部分博客或者书籍中都没有对这类问题的分析,网上绝大多数的博客都在分析这样的一个简单的问题:如果在函数中实例化一个类,那么内存是如何分配的?这个问题太简单了,都说烂了。不过我还不是太确定我的看法,和你的看法,到底是否正确。不知这位大神能否想出一些代码用于测试?或者帮忙分析下编译后的代码,以进行论证?
    十分期待您的进一步分析和讨论。
    你要我写代码验证,我真没那水平得出一个demo就能说明整个对象详细内存布局,不过我们可以从类的加载、初始化到对象的内存分配一步一步地进行分析:
    一、类在主动使用时才进行初始化包括:
         1.创建类的新实例;
         2.调用类中声明的静态非常量字段;
         3.调用类中声明的静态方法;
         4.使用反射方法生成类的对象;
         5.初始化一个类的子类;
         6.指定一个类作为启动类
         但是有几点需要注意:
          1.通过子类访问父类的静态非常量字段只会初始化父类,不会初始化子类;
          2.访问常量静态字段不会进行初始化;
          3.初始化接口并不要求父接口完成初始化;
         
        上面的我们都可以自己写测试代码来验证,由于比较简单,我就不贴代码了   ;二、类的加载,类加载分为3个步骤:
           1.通过全限定名找到定义类的二进制文件(即class文件);
           2.将二进制文件中的静态储存结构转为为方法区的运行时数据结构;
           3.生成一个代表类的Class对象;这个无法通过代码区验证,但是可以结合字节码和Java虚拟机内存的变化来观察,
    字节码可以使用javap来生成,虚拟机的内存变化可以通过jconsole来观察;三、类的验证不详述,因为不会涉及到内存的分配;
    四、类的准备是为类变量分配内存,如果是常量则在常量池中,如果是对象是在堆中;
    五、类的解析不详述,因为不会涉及到内存的分配;
    六、类的初始化,类的初始化是通过类构造器来实现的,主要是static语句块的合并;
    七、分配对象内存,大小由对象的属性值和Java虚拟机自身的对象内存布局来确定,如果对C有了解,
            我们把对象看成是结构体的类型数据综上所述,我们可以大致理解为:
    1.可以把对象看成C语言的结构体,这样方便我们理解,当然对象还包含其他的信息,如对象头、对其填充等等;
    2.有关类的信息的都在方法中,包括静态变量、常量、方法体的字节码等等;
    3.局部变量都在栈中、对象都在堆中、常量都在常量池(方法区的一部分)中;我们可以通过对象的访问,来进一步加深理解,如下图:
         
      

  16.   


    兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
    其实,我可以把意思说的更明白些:
    如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
    sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。我的类型定义错了,里面包含了重名的a和b,一个是int型的,一个是复合类型的。假设把复合类型的a和b的名字改成e和f,修改后如下:
    class A{
            int a,b;
            A e,f;
            //......
    }
    则修改后,当执行new A()时,是不是要在堆中分配4×6=64个字节的内存空间了?
    -_-#...果然是搞c++的,我不太记得int占多少空间了,总之创建A的时候会给A分配内存,这块内存里包含了ab两个int的长度,和两个指针ef(你可以这样理解),由于ef没有被初始化,实际上是指向null的说到这里,我突然想起一个问题来。如果e,f不是null,而是直接实例化,例如:
    class A{
            int a,b;
            A e=new A(), f=new A();
            //......
    }
    如果是这样,main函数中执行new A()后,A内部的e,f两个变量也要实例化,并要分配内存空间。但是执行e=new A()后,在堆中又为new A分配了一个空间。结果这个new A中又有两个实例变量e,f,于是又执行e=new A()……这样岂不是会一直循环下去么?内存很快就被耗尽了。不知道这种情况如何解决?或者jvm有啥规范?
      

  17.   


    还是这位大神的回答非常精准,看出了问题的本质。
    其实我看了一些书之后,也认为应该是这样分配的。只是网上绝大部分博客或者书籍中都没有对这类问题的分析,网上绝大多数的博客都在分析这样的一个简单的问题:如果在函数中实例化一个类,那么内存是如何分配的?这个问题太简单了,都说烂了。不过我还不是太确定我的看法,和你的看法,到底是否正确。不知这位大神能否想出一些代码用于测试?或者帮忙分析下编译后的代码,以进行论证?
    十分期待您的进一步分析和讨论。
    你要我写代码验证,我真没那水平得出一个demo就能说明整个对象详细内存布局,不过我们可以从类的加载、初始化到对象的内存分配一步一步地进行分析:
    一、类在主动使用时才进行初始化包括:
         1.创建类的新实例;
         2.调用类中声明的静态非常量字段;
         3.调用类中声明的静态方法;
         4.使用反射方法生成类的对象;
         5.初始化一个类的子类;
         6.指定一个类作为启动类
         但是有几点需要注意:
          1.通过子类访问父类的静态非常量字段只会初始化父类,不会初始化子类;
          2.访问常量静态字段不会进行初始化;
          3.初始化接口并不要求父接口完成初始化;
         
        上面的我们都可以自己写测试代码来验证,由于比较简单,我就不贴代码了   ;二、类的加载,类加载分为3个步骤:
           1.通过全限定名找到定义类的二进制文件(即class文件);
           2.将二进制文件中的静态储存结构转为为方法区的运行时数据结构;
           3.生成一个代表类的Class对象;这个无法通过代码区验证,但是可以结合字节码和Java虚拟机内存的变化来观察,
    字节码可以使用javap来生成,虚拟机的内存变化可以通过jconsole来观察;三、类的验证不详述,因为不会涉及到内存的分配;
    四、类的准备是为类变量分配内存,如果是常量则在常量池中,如果是对象是在堆中;
    五、类的解析不详述,因为不会涉及到内存的分配;
    六、类的初始化,类的初始化是通过类构造器来实现的,主要是static语句块的合并;
    七、分配对象内存,大小由对象的属性值和Java虚拟机自身的对象内存布局来确定,如果对C有了解,
            我们把对象看成是结构体的类型数据综上所述,我们可以大致理解为:
    1.可以把对象看成C语言的结构体,这样方便我们理解,当然对象还包含其他的信息,如对象头、对其填充等等;
    2.有关类的信息的都在方法中,包括静态变量、常量、方法体的字节码等等;
    3.局部变量都在栈中、对象都在堆中、常量都在常量池(方法区的一部分)中;我们可以通过对象的访问,来进一步加深理解,如下图:
         

    真够详细的呵呵
      

  18.   

    恩,自己多测试,能更好的理解相关的理论知识,另外建议可以使用jconsole来观察整个虚拟机的内存变化,jconsole会显示堆和方法区的内存使用情况和变化,也能检测出死锁或资源耗尽的问题。
      

  19.   

    看得出楼主有C++的编程基础,对内存分配和对象的内存布局应该能很好的理解。其实Java的内存分配和布局都是Java虚拟机实现的,没有一定的规则或规范,不同的Java虚拟机有不同的实现,有个大概清晰的概念即可。
      

  20.   

    不同的Java虚拟机有不同的实现.
      

  21.   

    对象都new出来了 不是static的成员变量  明显和对象一起
      

  22.   

    建议看下《深入理解java虚拟机》第二版,第二章说的很详细,