public class TestArray {
public static void main(String[] args) {
String  a1[] = new String [3];
String  a2[] = new String [3];
System.out.println(a1==a2);         //false;
System.out.println(a1[2]==a2[2]);        //true;    请用内存解析为什么是true!
a1[1] = new String("hello"); 
  a2[1] = new String("hello"); 
System.out.println(a1[1] == a2[1]);   //false;   请用内存解析 为什么是false;  
//并对照上面的true,说出区别!

a1[1] = null;
a2[1] = null;
System.out.println(a1[1] == a2[1]);   // true; 对照所有的解析,说出地址分析区别!
}
}
/* 提问:  A a[] = new A [a.length];
1.定义一个数组a是new出来的, 里面分配了a.length个空间吗?. 
2.这些空间有没有各自的地址以区分他们?例如前驱,后继!
3.== 号是不是地址和值两项的比较?
4.==号是不是只有两项全为true时,才为true?
5. a[i] 代表什么,是代表了值,还是地址,还是代表了两项?
6. 如果a[i] 只代表了一项,那另一项是靠什么来区分?.  
7.a[i] == a[j] ; 为true时;  有没有比较他们的地址?,
如果没有! 请说出为什么?
8.综合上述 说出 引用,指针,地址,变量,内存解析和区别!
*/

解决方案 »

  1.   

    A a[] = new A [a.length]; 
    此时候应该还未分配地址空间,应该是都指想同一中间数据结构,所以System.out.println(a1[2]==a2[2]);   这个应该是true;a1[1] = new String("hello");  
      a2[1] = new String("hello");  
    System.out.println(a1[1] == a2[1]); 此时才为a1[1]、a2[1]在堆中分别分配了空间,所以会显示false,如果你System.out.println(a1[2] == a2[2]); 你会发现依然是true
      

  2.   

    public class TestArray { 
    public static void main(String[] args) { 
    String  a1[] = new String [3]; 
    String  a2[] = new String [3]; 
    System.out.println(a1==a2);         //false;  比较的是两个数组在内存中的首地址
    System.out.println(a1[2]==a2[2]);        //true;    因为String类在内存中有个缓冲池,所以你不赋值给它的时候,他们都是NULL,用同个缓存池中的地址 (你可以用StringBuffer类去对比一下)
    a1[1] = new String("hello");  
      a2[1] = new String("hello");  
    System.out.println(a1[1] == a2[1]);   //false;同上面,因为创建了新空间了
    a1[1] = null; 
    a2[1] = null; 
    System.out.println(a1[1] == a2[1]);   // true; 同上


      

  3.   

    String  a1[] = new String [3]; 
    String  a2[] = new String [3]; 
    System.out.println(a1==a2);         // ==  用于两个对象之间 比较引用 所以返回false
    System.out.println(a1[2]==a2[2]);        // a1[2]和a2[2]都是 null 所以返回truea2[1] = new String("hello");  
    a2[1] = new String("hello"); System.out.println(a1[1] == a2[1]);   //false;   用于两个对象之间 比较引用 所以返回false本人小菜哇 说错了别怪 
      

  4.   

    去看一下JVM的内存管理机制 还有系统的内存管理机制在各个不同类中运用的文档就行了
      

  5.   

    public class TestArray {  
    public static void main(String[] args) {  
    String  a1[] = new String [3];  
    String  a2[] = new String [3];  
    System.out.println(a1==a2);         //false;  比较的是两个数组在内存中的首地址 
    System.out.println(a1[2]==a2[2]);        //true;    因为String类在内存中有个缓冲池,所以你不赋值给它的时候,他们都是NULL,用同个缓存池中的地址 (你可以用StringBuffer类去对比一下) a1[1] = new String("hello");   
      a2[1] = new String("hello");   
    System.out.println(a1[1] == a2[1]);   //false;同上面,因为创建了新空间了 
    a1[1] = null;  
    a2[1] = null;  
    System.out.println(a1[1] == a2[1]);   // true; 同上 
    }  
    }  
      

  6.   

    String  a1[] = new String [3];
    String  a2[] = new String [3];   在这里创建了两个数组,他们的引用肯定不一样!System.out.println(a1==a2); 自然没什么好说的! System.out.println(a1[2]==a2[2]); 数组里面在你没有赋值前都是为null的,他们肯定相等阿!a1[1] = new String("hello"); 
    a2[1] = new String("hello"); 
    System.out.println(a1[1] == a2[1])  a1[1],a2[1]别new创建了一个对象,他们的地址也肯定是不同的,如果你改成
    a1[1] = new String("hello"); 
    a2[1] = new String("hello"); 
    这样他们的地址肯定是一样的了,a1[1] = null;
    a2[1] = null;
    System.out.println(a1[1] == a2[1]);  你又再次清空他的引用,他们的他们引用为空,肯定判断地址是相同的,跟你的第一个问题是一样的!1.定义一个数组a是new出来的, 里面分配了a.length个空间吗?.  
    他是分配了a.length个空间,但是空间里面保存的都是引用,也就是地址,如果你没赋值前都是null,这些空间有没有各自的地址以区分他们
    这个空间里面保存的是一个引用,他就是用a[下标]去取的!==号是不是地址和值两项的比较
    ==号比较对象只是比较地址不比较值的!比较值类型自然就是比较值了!4.==号是不是只有两项全为true时,才为true? 
    上面的问题都知道了,这个问题没必要回答了吧!5. a[i] 代表什么,是代表了值,还是地址,还是代表了两项? 
    代表引用,也就是地址!6. 如果a[i] 只代表了一项,那另一项是靠什么来区分?.   
    有了引用自然可以找到值,String str = new String ("abc");这里str也是引用,为什么你输出str会等于abc为什么不是地址呢?如果要问这样的问题。我确实也不知道怎么回答你!7.a[i] == a[j] ; 为true时;  有没有比较他们的地址?, 
    就是在比较地址!在java里面没有指针,有的人把引用也当作指针,举例来说。java的引用相当于电视的遥控,有了遥控就可以控制换台,在java中,引用就是地址,
      

  7.   

    楼上的请回答:5. a[i] 代表什么,是代表了值,还是地址,还是代表了两项?  
    代表引用,也就是地址!String  a1[] = new String [3]; 
    String  a2[] = new String [3];   在这里创建了两个数组,他们的引用肯定不一样!System.out.println(a1==a2); 自然没什么好说的!  System.out.println(a1[2]==a2[2]);   这是两个数组里的地址,  他们地址怎么会为true呢?
      

  8.   

    5. a[i] 代表什么,是代表了值,还是地址,还是代表了两项?   
    代表引用,也就是地址! 
    String  a1[] = new String [3];  
    String  a2[] = new String [3];   在这里创建了两个数组,他们的引用肯定不一样!System.out.println(a1==a2); 自然没什么好说的!   System.out.println(a1[2]==a2[2]);   这是两个数组里的地址,  他们地址怎么会为true呢?>>>>>>a1[2]记录的是String对象的地址,  String对象的地址记录的才是里面数值真正的空间
      

  9.   

    public class TestArray { 
    public static void main(String[] args) { 
    String  a1[] = new String [3]; 
    String  a2[] = new String [3]; 
    System.out.println(a1==a2);         //false; 
    System.out.println(a1[2]==a2[2]);        //true;    这个比较的不是地址,而是地址里存的值, 
    a1[1] = new String("hello");  
      a2[1] = new String("hello");  
    System.out.println(a1[1] == a2[1]);   //false;   两个里边村的是string对象的地址,因为是两个不同地址的string对象,所以不等;   
    //并对照上面的true,说出区别! a1[1] = null; 
    a2[1] = null; 
    System.out.println(a1[1] == a2[1]);   // 因为数组里面的地址都是空,所以相等.


    你可以把== 和equal()作以下对比
      

  10.   

    9楼的看法 , 我是最满意的, 因为我觉得他说的对!如果有人认为他的解释是错误的,请说说你的看法!~你可否在补充一下内存管理机制方面的问题呢?
    也就是说:  stack , heap  data segment, code segment, 里面存放的东西!~stack 是不是存放 变量 和引用?
    heap 是不是只存放的指针属性( 也就是连接地址)
    data segment 里存放的究竟是什么, 说是常量和静态变量, 只有这些吗?.
     按照你的解释,string对象的地址记录才是里面数值真正的空间
    也就是说我们建立了一个数组之后, a[i] 只是在代表引用,它指向最后的指向空间吗?
    那么再看下面这个!说出你的解释:a1[1] = new String("hello");   
      a2[1] = new String("hello");   好象是对象最后都指向了data segment里的"hello";
    可是为什么他们却不相同呢?

      

  11.   


    1.定义一个数组a是new出来的, 里面分配了a.length个空间吗?.   
    String[] s = new String[5];jvm中有三类内存区域,栈内存、堆内存和静态存储。
    栈内存(stack)在随机访问存储器(RAM)内,一般通过堆栈指针进行操作,它是按顺序分配内存空间的,当堆栈指针下移一位则分配一个单元内存空间,上移则释放空间。String[] s = new String[5];这个语句是在栈内存中分配了五个空间,它们可以通过变量s[0]...s[5]进行索引,它的内容是在堆内存中分配的5个空间的内存地址。我们可以把它们当作5个指针。
    例如:Java的基本数据类型(int byte boolean ....)分配内存都是在栈内存上。堆内存(heap)同样在RAM中,它保存对象和前者不一样,编译器不知道将要分配多大内存空间给该对象,也不知道这个对象要存在多长时间,用它保存数据将会获得很大的灵活性。我们都知道,JAVA中我们无法直接做任何回收的动作,而只能提示jvm该回收垃圾了。那么堆内存中的对象,时刻要被java回收机制线程监控,判断是否该变量已经超过了作用域,从而回收它。灵活性和回收机制,让堆内存比栈内存更消耗系统资源,效率更低。当我们做s[0] = new String("123");才完成对堆内存中s[0]指向的内存空间初始化,我们才可以引用这个对象。
    当你调用System.out.println(s[0]); jvm将会从s[0]中读取到它的内存地址,将内容输出在控制台上。而如果你输出的是s[0].toString();那么你将看到s[0]所保存的内存地址。静态存储(static)同样在RAM中,这里的静态意味着位置固定,它在类被加载时,就已经在RAM中分配了空间,并完成了初始化。例如:
    A a;这个类声明语句,就已经完成了初始化。2.==号是不是地址和值两项的比较 
    “==”比较的是内存地址,例如:
    String s1 = "123";
    String s2 = "123";
    s1 == s2,这里比较的是栈内存中s1与s2的值。java中,比较对象的内容是通过s1.equals(s2);这种方式进行的。
    当然上面的比较结果是true的。但是下面这种情况,结果就是false:
    String s1 = "123";
    String s2 = "1" + "23";
    我们通过equals方法比较,才能得到true的结果。
    5. a[i] 代表什么,是代表了值,还是地址,还是代表了两项?  
    a[i]是引用,你可以把它仅仅当作一个名字,它的内容是内存地址,而当你调用它时,jvm拿给你的是它所保存的内存地址(即heap内存上的地址)上的实际值。以前很多关于java值传递和引用传递的帖子,总结一下吧!
    class A {
      int i = 10;
    }int i = 100;
    这里有两个对象a.i与i(a是A的一个实例)。接下来有一个方法,如下:
    public void Add(int i) {
      i = 20;
    }
    分别调用:
    Add(a.i);
    Add(i);当你输出a.i和i时,你会发现:
    a.i = 20; 
    i = 100;
    a.i传递的是引用,Add方法将a.i的指向转变了,它不在指向heap堆中的内容为“i = 10”的对象了,而指向“i = 20”的对象;i传递的是值,也就是说是一个副本,Add方法修改的只是一个copy,而栈内存中i还是等于100。
     6. 如果a[i] 只代表了一项,那另一项是靠什么来区分?.    
    7.a[i] == a[j] ; 为true时;  有没有比较他们的地址?,  
    你这样问,让我怎么回答你呢?
    “在java里面没有指针,有的人把引用也当作指针,举例来说。java的引用相当于电视的遥控,有了遥控就可以控制换台,在java中,引用就是地址”
    java中指针无处不在,只是说,作为程序员你无法感觉到它的存在,无法直接操作它。
      

  12.   


    但是下面这种情况,结果就是false: 
    String s1 = "123"; 
    String s2 = "1" + "23"; 
    我们通过equals方法比较,才能得到true的结果。 
    LS的 上面用s1 == s2;的出来的也是true!
      

  13.   

    但是下面这种情况,结果就是false:  
    String s1 = "123";  
    String s2 = "1" + "23";  
    我们通过equals方法比较,才能得到true的结果。  
    s1 与 s2还是指向同一个内存地址!
      

  14.   

    指明楼上你的错误,  
    有些说的是对的,可是不知道为什么还是走向误区了呢?
    虽然说了很多, 但是还是得不到意想的结果!~第一个:
    当然上面的比较结果是true的。但是下面这种情况,结果就是false: 
    String s1 = "123"; 
    String s2 = "1" + "23"
    //错误了,  比较s1==s2,结果还为true! 由此可看比较的不是内存地址!~

    第二个:
    例如:Java的基本数据类型(int byte boolean ....)分配内存都是在栈内存上。 //根据我目前掌握知识的理解, 变量的分配才在栈内存中,而且不光是基本数据类型,是包括所有的数据类型,
    常量是分配在data segment中!

    第三个:
    当我们做s[0] = new String("123");才完成对堆内存中s[0]指向的内存空间初始化,我们才可以引用这个对象。//(老师讲的) : 堆内存中就是存放那些new出来的东西,  可是老师并没有说new出来的东西究竟是什么, 根据我理解new出来应该属于对象了,    所以对堆内存里面存放的究竟是地址还是别的内容,请解答一下!
      

  15.   

    String str1 = new String("abc");
    String str2 = new String("abc");
    String str3 = "abc";
    String str4 = "abc";
    System.out.println(str1 == str2);   //false 
    System.out.println(str3 == str4);   //true
    以上这个结果可能大家都知道,但具体的原因是什么啊?str1,str2是new的,而两个是直接赋值的
      

  16.   

    讨论的不是这个问题!~  你能看下问题吗?.赋值 其实也相当与引用,  在这里要说明的是内存的指向和寄存问题,
    再一个说明的是数组的问题,   
    刚才解释第二个的时候说的有点漏了, 静态变量不在栈中, 而在data segment!期望得到内存解析的一个完整的图!~ 我的QQ是42578670!~ 希望大家可以来探讨!
      

  17.   

    指明楼上你的错误,   
    有些说的是对的,可是不知道为什么还是走向误区了呢? 
    虽然说了很多, 但是还是得不到意想的结果!~ 
    第一个: 
    当然上面的比较结果是true的。但是下面这种情况,结果就是false:  
    String s1 = "123";  
    String s2 = "1" + "23" 
    //错误了,  比较s1==s2,结果还为true! 由此可看比较的不是内存地址!~ 第二个: 
    例如:Java的基本数据类型(int byte boolean ....)分配内存都是在栈内存上。  //根据我目前掌握知识的理解, 变量(静态变量除外)的分配才在栈内存中,而且不光是基本数据类型,是包括所有的数据类型, 
    常量是分配在data segment中! 第三个: 
    当我们做s[0] = new String("123");才完成对堆内存中s[0]指向的内存空间初始化,我们才可以引用这个对象。 //(老师讲的) : 堆内存中就是存放那些new出来的东西,  可是老师并没有说new出来的东西究竟是什么, 根据我理解new出来应该属于对象了,    所以对堆内存里面存放的究竟是地址还是别的内容,请解答一下! 
      

  18.   

    楼主为什么对地址和指针那么执着?
    是不是以前研究C/C++比较多的缘故?我对这个问题的看法是:Java里面没有指针,就无法看到地址,我们都知道==就是比较地址而已,这是永远不变的!
    如果楼主觉得诧异,那么我列举这个例子:public class Test{
        private staitc String ss ;
        
        public static void main(String args[]){
            String[] aa = new String[3];        System.out.println(ss==aa[2]);   //楼主觉得这会是true还是false呢?
        }
    }显然是true,因为大家都是null,所有的null在内存中就是同一地址,否则Java里面那么多没初始化的null,难道每个都需要占据一块内存地址空间么?
    如果楼主一定要追寻它的内存地址是多少,那不是属于Java的范畴,在Window内存分配中有表格列出来那片区域,可以找本Windows核心编程查查就知道了
      

  19.   

       指出楼上的错误:        显然是true,因为大家都是null,所有的null在内存中就是同一地址,
    String  a3[] ={"中国","日本","美国"};
    String  a4[] ={"中国","日本","美国"};
    System.out.println(a3[1]==a4[1]);这会不是null了吧,  可是还是 true,  你说比较地址, 这个还是同一指向吗?.不是说对地址和指针执着, 是真的想搞清楚内存解析,因为我看的视频是这样讲过来的啊, 可是到这里不明白了,毕竟我是在自学,只能看视频,没有办法跟老师交流,所以才在这里提问出来!~也是希望能解答自己心中的那一个困惑吧!~

      

  20.   

    呵呵,我哪里说错了么?
    返回true一定代表是同一个地址,想都不用想也不用怀疑。因为在Java里面你看不到地址,
    我知道你肯定会说如果是这样的话呢?a3[2]=new String("中国");
    a4[2]=new String("中国");这样就是false了,对吧?其实这都没问题啊,所有通过默认定义的String在内存中都是一个地方存的,所以下面是true
    String a = "hello";
    String b = "hello";a==b // true,因为内存里面只有一个hello字符串,也就是存储在前面几位仁兄说的Buffer池中,地址当然一致,是虚拟机给new出来的String a = new String(“hello”);
    String b = new String(“hello”);
    a==b //false因为显式使用了new,虚拟机的顺序的先开辟两块内存地址,再分别赋值为hello的,那么这个时候地址还一样么?呵呵,楼主如果要想明白,先让指针的
    概念从脑海里面消失吧
      

  21.   


    听你这么解释的话,  你听听我的理解看对不对? a==b 比较的是地址, 
    地址是存放在堆里面的,  只有 new出来的才会有地址存在,不是new出来的 只能作为元素,
    元素是分为变量和常量的,不存在对象,  因为对象也是new出来,没有new出来,只能作为对象引用的一个变量,变量是放在栈里的!所以: String  a3[] ={"中国","日本","美国"}; 
    String  a4[] ={"中国","日本","美国"}; 
    他们的a3[1]==a4[1]; 他们都指向了同一个常量, 而不是对象,
    例如: string s="中国"  a3[1]==s==a4[1]; 他们都指向了同一个常量! 
    所以a3[1] ,a4[1];他们只是一个变量的引用, 他们的地址其实是 a3[] ,a4[]这两个对象,再按你的解释: ==是表示比较地址的;
    他们最后的指向都指向了 data segment 中的字符串常量"中国" ;所以它们的地址相同!~如果 a3[1]= new string("中国");
    a4[1]= new string("中国") ;  
    他们是new出来的, 是放在堆里的一个对象, 有地址的,所以不同,
    可是他们的值却是相同的, 而现在a3[1] ,a4[1]已不再是变量, 
    它们现在被当作了一个对象来使用,
    而对象是有自己的地址的, 所以他们的比较为false;

    不知道我这样解释是否合理呢??????????????
      

  22.   

    呵呵,你的精神我很佩服,不过我现在无法说你的理解就是对的,
    Java中String对象是不可变的,关键看你怎么理解这句话这两天我很想尽快查证这个问题,然后再给你一个最科学的解释。
      

  23.   

    楼主不要把c/c++里学来的概念硬套在java里!java里没有data segment的说法。常量在java中是保存在常量表(constant table)里的。
    23楼的理解部分是正确的。如果你是字符串常量,那么只要这些常量是内容相同的,编译时编译器会自动把它们合并成同一个常量,jvm在加载类的时候,对于常量也会合并。这也就是为什么 s1="123" 和 s2="1"+"23" 用==比较会相等的原因,因为它们被指向了同一个地址。
      

  24.   

    更正一下:“指向了同一个地址”这个说法不好,因为在java里程序员是得不到地址的,除非你写jni。说法改成“引用了同一个String常量”。
      

  25.   

    楼上说的很对
    那个例子我也做过如果String a1="中国";
    String a2="中国";此时在java的栈内存保存有a1,a2
    而在堆内存中只保存一个String对象(中国)
    a1和a2都同时指向那个内存地址所以这个时候a1==a2为true;若String a1=new String("中国");
    String a2=new String("中国");
    此时在堆中就有两个值为"中国"的String 对象,
    a1指向其中的一个,a2指向另外一个所以此时a1==a2 就为false,因为他们的指向对象的地址不同最后补充一句,这个帖大家讨论了这么多,楼主也不要吝啬一点分数
      

  26.   

    更正:有人说我这个是想知道string 对象的, 其实不是,  
    这个不光是在string对象里, 在所有的对象里 都是这样的!~

      

  27.   

    再次更正: 28楼提到分数了!其实这个号也没多少分数, 只是为了讨论问题,将问题解决,
    也是大家对java交流意见的增强和认识,  
    分数也不是很多!~到没有说吸引什么人! 只是希望得到一个完好的解释,
    人家常说:"胜利不是因为拿到了奖杯!而是因为拿到奖杯之后那种成就和喜悦!"当发现一个非常合理的答案的时候, 我就会把分数送出去的!~ 
      

  28.   

    “当然上面的比较结果是true的。但是下面这种情况,结果就是false:  
    String s1 = "123";  
    String s2 = "1" + "23" 
    //错误了,  比较s1==s2,结果还为true! 由此可看比较的不是内存地址!~ ”没有敲代码就下了结论,不好意思!我只是举个例子,s1 == s2比较的确实是内存地址。
    你这样比较一下,就是false了。
    String s1 = "123";
    String s2 = new String("1") + "23";
    常量的拼接得到的结果应该跟前者是一样的。但通过new产生对象,就在heap堆中new了一个内存地址,再次拼接,地址就不一样了。“第二个:  
    例如:Java的基本数据类型(int byte boolean ....)分配内存都是在栈内存上。   //根据我目前掌握知识的理解, 变量(静态变量除外)的分配才在栈内存中,而且不光是基本数据类型,是包括所有的数据类型,  
    常量是分配在data segment中!  
    ”如果你留心看上面的帖子,就知道了,我并没有说只有基本数据类型才分配在栈内存上啊!所有的引用型变量都是会在占内存分配空间,而当你对他进行初始化时,使用关键字new时,会在heap堆中分配内存空间。栈内存保存的是堆内存的地址,而堆内存保存的是对象的内容。
    “第三个:  
    当我们做s[0] = new String("123");才完成对堆内存中s[0]指向的内存空间初始化,我们才可以引用这个对象。  //(老师讲的) : 堆内存中就是存放那些new出来的东西,  可是老师并没有说new出来的东西究竟是什么, 根据我理解new出来应该属于对象了,    所以对堆内存里面存放的究竟是地址还是别的内容,请解答一下!”堆内存存放的是对象的机器码(个人理解)。------------------------
    String对象是一个特殊的对象,它是一个引用型的对象,但它有自己的特点,就是它无法被更改。
    举例:
    String s = "123";(jvm为这句代码分配了两块内存空间,堆内存保存字符串对象"123",而栈内存则保存堆内存的地址)
    任何针对s的拼接,剪切的操作,都只是更改了栈内存中的内容,换句话说,只是将s指向了其他的字符串。而原本堆内存中的字符串对象"123"没有被更改。
    java中可以更改的字符串对象是StringBuffer。
      

  29.   

    “当然上面的比较结果是true的。但是下面这种情况,结果就是false:  
    String s1 = "123";  
    String s2 = "1" + "23" 
    //错误了,  比较s1==s2,结果还为true! 由此可看比较的不是内存地址!~ ”没有敲代码就下了结论,不好意思!我只是举个例子,s1 == s2比较的确实是内存地址。
    你这样比较一下,就是false了。
    String s1 = "123";
    String s2 = new String("1") + "23";
    常量的拼接得到的结果应该跟前者是一样的。但通过new产生对象,就在heap堆中new了一个内存地址,再次拼接,地址就不一样了。“第二个:  
    例如:Java的基本数据类型(int byte boolean ....)分配内存都是在栈内存上。   //根据我目前掌握知识的理解, 变量(静态变量除外)的分配才在栈内存中,而且不光是基本数据类型,是包括所有的数据类型,  
    常量是分配在data segment中!  
    ”如果你留心看上面的帖子,就知道了,我并没有说只有基本数据类型才分配在栈内存上啊!所有的引用型变量都是会在占内存分配空间,而当你对他进行初始化时,使用关键字new时,会在heap堆中分配内存空间。栈内存保存的是堆内存的地址,而堆内存保存的是对象的内容。
    “第三个:  
    当我们做s[0] = new String("123");才完成对堆内存中s[0]指向的内存空间初始化,我们才可以引用这个对象。  //(老师讲的) : 堆内存中就是存放那些new出来的东西,  可是老师并没有说new出来的东西究竟是什么, 根据我理解new出来应该属于对象了,    所以对堆内存里面存放的究竟是地址还是别的内容,请解答一下!”堆内存存放的是对象的机器码(个人理解)。------------------------
    String对象是一个特殊的对象,它是一个引用型的对象,但它有自己的特点,就是它无法被更改。
    举例:
    String s = "123";(jvm为这句代码分配了两块内存空间,堆内存保存字符串对象"123",而栈内存则保存堆内存的地址)
    任何针对s的拼接,剪切的操作,都只是更改了栈内存中的内容,换句话说,只是将s指向了其他的字符串。而原本堆内存中的字符串对象"123"没有被更改。
    java中可以更改的字符串对象是StringBuffer。
      

  30.   

    如果你留心看上面的帖子,就知道了,我并没有说只有基本数据类型才分配在栈内存上啊!所有的引用型变量都是会在内存分配空间,而当你对他进行初始化时,使用关键字new时,会在heap堆中分配内存空间。栈内存保存的是堆内存的地址,而堆内存保存的是对象的内容。
      

  31.   


    首先, 先感谢下32楼同志, 把我的错误也分析的很透彻了!~
    对您回答了这么多楼,我也表示衷心感谢了!~ 真的是一个 good man!可是看了你的问题之后,我又产生了雾水! 你说:栈内存保存的是堆内存的地址,而堆内存保存的是对象的内容,
    对您这句话的提问:   
    1.你所说的内容是不是指得数据属性?. 而地址就是指针属性了! 在数据结构上说!
    2.数据类型的地址应该都在常量表中吧(data segment)?. 
    3.我所理解的是堆内存保存的是new出来的地址,  new也是新建了一个地址,
    所以堆内存应该是预备内存, 是为准备建立新地址而设立的!~ 建立了新的地址之后,将新的数据排序属性放进去!形成了新的内容!
    4.栈内存中应该放的是变量!按照你这句话我所感觉的理解好象就是:
    栈内存存放的是堆内存的地址, 那应该属于结点中的指针属性了!
    5.变量的变量名是不可变的! 而你说这个是地址?.这个就让人理解不透了!
    根据我的理解,变量分为变量名和变量值,而这个值在 堆内存和data segment中去寻址, 栈内存中只表示了变量名!
      

  32.   

    感谢“bxdg42578670 ”的疑问,其实我的理解有时候也掺入了一些个人的臆测,不求甚解,大约就是这样吧!
    我也不清楚,到底使用关键字new后,jvm到底做了什么操作?堆内存到底是如何对象?(可能这些涉及到数据结构和操作系统的知识)。
    google出来的结果,大家大多在解释,new做了什么事情,而没有解释如何做这些事情。
    我想短时间也没办法理出个头绪出来。我查阅了一些资料,能肯定的大多如下:
    正如你所说变量分为变量名和变量值。java在生成基本数据类型或引用类型的对象时,都会在栈内存中分配内存空间。
    如果是基本数据类型,例如:
    int i = 0;
    jvm首先会在栈中创建一个变量为i的引用,然后遍历栈是否有10这个整型值,若没有则保存这个值(至于怎么保存,我不确定,二进制代码?maybe),然后将a指向这个值;若有则直接指向这个值。
    这样做的原因是基本数据类型通常比较小,可以实现决定分配多大内存空间,而这也是堆栈操作必须的:先进后出,在入口处就必须决定它们占用的空间大小以及生存时间。栈内存因为它的存储特性和要求,决定了它不错的访问速度,而它的共享性更是大大增加了内存的利用率。如果是引用型对象,则会在栈中创建一个变量引用(至于jvm怎么引用,我不清楚),而栈内存保存的是堆内存的首地址。如果是new产生的对象,那么不论是否已经有了一样的对象,都回在堆内存中从新分配一个内存空间,存储这个对象的二进制代码。
    今天任务多,偷偷在上班时间回帖是不对地,要赶任务了,晚上上来看。
      

  33.   

    我绝对楼主的基础还要学一下,第一,java创建值类型和创建对象他的内存是怎么分配的?
    第二,String是一个特殊的对象,他是不可变的
    第三,==和equals的区别。如果这三个问题你都能完全明白的话,你的问题很容易解决!我博客有string和==与equals的文章,讲的很细了! 
    值类型的创建分配内存是在栈上分配的,对象创建是在堆上分配的! 但是他的引用是在栈上分配的!
    楼主去看看堆和栈的区别吧,栈上分配需要知道其大小和生命周期,分配内存只需要向上移动指针就可以分配。速度很快,
    堆上分配比较慢,但是他的好处就是不需要知道他的大小和生命周期!
      

  34.   

    我靠,楼主真执着,叫人佩服。但是楼主又那么专注于地址,java中没有这个概念的,又叫人可恨,希望你用java的思想来思考java中的问题。
    你提了那么多问题+其他人那么多的回答,我没有全部看完。
    1、A[] a = new A[100];//已经分配空间了,在stack中分配了空间存a;在hea中创建了一个新对象(Array类型),这个对象可以存100个A的对象;stack中的a指向heap中新创建的这个对象(求你了,不要说地址)。这个对象中存了100个引用,分别指向一个A的对象。
       刚开始,数组没有初始化,所以里面的100个引用都是指向null,所以都相等。
       我有事,回来再回答你。
      

  35.   

    呵呵,   不好意思,  这次回来  又是推翻结果的!~~
    指出上面回答出现的错误啊!~纯属交流!~第一个:
    int i = 5;地址是0x0012FF7c,值是5、
    char c = '5'地址是0x0012FF78,值是53
    //
    上面有人说是值相同, 地址不同,   在现在看来  地址和值都是不同的!
    所以还是无法说明==是比较地址的! 
    不过在对象看来是这样的!其他的类型无法说明
    第二个:     先说说39楼这个同志回答的吧!
    1、A[] a = new A[100];//已经分配空间了
    ,在stack中分配了空间存a;在hea中创建了一个新对象(Array类型),
    //
    这个对象是 A类型的!~ 
    可以存100个数据元素,并非要是A的对象,元素是任何类型的;
    2. 刚开始,数组没有初始化,所以里面的100个引用都是指向null,所以都相等。// 数组已经初始化了,  都指向了null!~
    第三个:  int a =5, b =5; a==b;
    //a,b的地址是不同的,因为它们是不可变的,都有自己的地址!
     可是今天听说基本数据类型是放在栈里的!
    最后竟然比较的是它们的值!第四个:     int [] a;
    //这应该说明是在栈空间里声明了这么一个数组!
    栈的原理是"后进先出" , 那么a[5]a[4]a[3]...是这样出去的吗?
    如果是这样的话好象违背了数组的顺序结构了!
    a[i]  究竟放在哪里呢?. 如果new了50个数组,那50个a[i]是不是在栈里生成的呢?第五个:   new 关键字!
    //new 的意思应该是新生成了一个地址吗! 有区分他们的地址属性!~
    那么我们平常使用的没有new的对象或者数据元素,他们是不是都是唯一的地址呢?.象这样的:   char a = 'A' ; int b = 65;
    他们指向的 究竟是不是一个地址呢?
      

  36.   

    再次给楼主一个提醒:java语言里是没有地址概念的,除非你是在做jvm,所以不要总是用地址这个概念来说事。==比较,是比较这两个值是不是逻辑意义上的相等。对于primary类型来说,就是比较值,这样才符合平常的惯例;对于引用型数据,也就是派生于Object的类(包括Object自己)的实例,你无法定义一个普遍意义上的相等来符合平常的惯例,所以定义为,必须两个引用是引用了同一个实例,==比较才相等。int i = 5;地址是0x0012FF7c,值是5、 
    char c =  '5 '地址是0x0012FF78,值是53 
    ---
    5 == '5' 会把 '5' 换成其int值,也就是十进制的53,再和5比,显然不等。第四个:     int [] a; 
    //这应该说明是在栈空间里声明了这么一个数组! 
    ------
    你自己对照第二个去理解吧。这里只是声明了一个变量叫a,其值是一个元素为int的数组,或者说a引用了一个元素为int的数组。这个数组和a是两回事!假如代码如下:
    int[] a, b;
    a = new int[100];
    b = a;
    那,这个时候b和a会引用了同一个数组。
    象这样的:   char a =  'A ' ; int b = 65; 
    -------
    一样,把'A'换成其对应的int值,是65,所以a==b返回真。
    给楼主一个建议,随便找本java语言的书,比如tij,都会讲到这些概念,这些都是最基本的。希望楼主不要总是把c/c++的概念硬套到java里来,你就会理解很多东西,否则就是钻牛角了。
      

  37.   

    其实, 我要问的很简单!~ 没想到竟罗嗦了这么多!~可能是我不太会提问吧!~ 慢慢学吗!~ 提问也是一门学问啊!~
     其实有人直接把一个程序的内存分析完整的告诉我,应该就了解了吧!
    废话不说那么多了!切入正题:[color=#FF0000]
    如果你说java没有地址之说的, OK 我不反驳, 想必你学变量的时候应该看到地址了!
    变量名就是地址!这便是"按名访问" 原则;
    定义的类型是给变量分配足够的空间!
    而这个空间里存放的就是你写入的数据了!这是数据结构的原理, 所以,它不光是对java 而言的!
    int []a//你自己对照第二个去理解吧。这里只是声明了一个变量叫a,其值是一个元素为int的数组,
    或者说a引用了一个元素为int的数组。这个数组和a是两回事!假如代码如下: 你这句话说的是对的! 声明了一个变量a , 
    并在栈空间里分配了为int类型变量足够的空间! 
    这个是我的补充!~再补充查到的一个知识点: 
    变量名是不可变的, 也就是说它的地址是唯一的,分配了不可再改变!因为变量是有生命周期的,出了大括号就不存在了,所以它的地址是在栈里的!
    出栈就消失了!~
    它的值究竟在不在栈里呢?> 不太清楚, 估计基本数据类型是在栈里的!
    所以基本数据类型==是比较值!不知道你可否还能为 这句话 再做补充,因为"[]" 并没有解释到~!~
    第三个:
    int[] a, b; 
    a = new int[100]; //new  的 地址  肯定是在堆里了,  这点大家都不怀疑!
    这个时候 变量a 的地址是不可变的!~ 好,抛开地址不谈, 
    我们谈空间, 这个小块内存肯定是在堆里了!~ 到这里你看出点疑惑了吗?.. 请您把这里解释通!~~
      

  38.   

    变量名就是地址!这便是"按名访问" 原则; 
    -----
    这句错误,在java里,对于Object的子类对象来说(包括Object本身),变量名是引用,不是地址。int []a 
    你这句话说的是对的! 声明了一个变量a ,  
    并在栈空间里分配了为int类型变量足够的空间!  
    这个是我的补充!~ 
    ---------
    补充是错误的,应该是:在栈空间里分配了一个空间,这个空间用来存放一个对int数组的引用,而不是存放int数组本身。到这里你看出点疑惑了吗?.. 请您把这里解释通!~~ 
    --------
    没看出疑惑啊,请明确指出。
      

  39.   


    我觉得你应该看看书!~   
    声明变量的作用是什么?>. 
    1.识别!
    2.分配空间!
    你自己去看看书 就知道变量的作用是什么了!~  

    我说的看的出的疑惑就是指,  
    栈空间有地址和空间, 堆里也有地址和空间!~
    很明显:
    int[] a, b;  
    a = new int[100];    
    很明显,这经过了赋值运算的一个过程!查过的解释:
    赋值是将 "=" 右边的值,存储到变量中!
    赋值是一个将 " 地址 和值" 两项 都赋值过去!(这条目前没有理解)
    赋值两边的类型必须相同;
    这样才保证了赋值空间的大小!~
    这说明 a经过赋值过程,确实代表了这个这个数组!
      

  40.   


    栈空间有地址和空间, 堆里也有地址和空间!~ 
    很明显: 
    int[] a, b;   
    a = new int[100];     
    很明显,这经过了赋值运算的一个过程! 
    ----------
    楼主一直都是在陈述,一个问句都没有,何惑之有?提醒楼主多次了,不要用地址这个概念来考虑问题,用引用,这个是java里明确给出的概念。当然,引用最终是靠地址来实现的,但从概念上来说,我们把这个地址叫做引用。但从另一个角度想,目前的计算机需要用地址来表示引用,如果有另外一个体系结构的计算机,我可以完全不用地址而一样能表示引用。所以说,地址是与jvm实现相关的,而引用则是java语言自身的概念,独立于jvm。声明变量的作用是什么? >.  
    1.识别! 
    2.分配空间! 
    ----------
    你的这两句说的没错,变量说白了就是个“助记符”!没有什么特殊意义。我所强调的是:对于primary类型的来说,变量里面存的是;对于Object的子类(包括Object本身)来说,变量里存的是引用。我并不care变量本身的在哪里,是在堆还是在栈都没关系,我care的是变量里存的东西。new int[100] 结果是在堆上生成一个int数组的存储空间,这个空间可以存放100个int类型的,并且缺省的,这些都是0。如果改为 new String[100],则结果在堆上生成一个String数组的存储空间,这个空间可以存放100个String类型对象的引用,并且缺省的,这些引用都是null。这里是对数组的初始化,是java规范里要求的,不应该理解为普通意义上的赋值,因为并没有调用赋值操作。1个int需要4个字节来保存,但new int[100]并不是仅仅生成100*4个字节,还需要为管理这些内存多申请一小块(内存头),具体多大取决于虚拟机实现,用于对这100*4个字节的管理。这也是对楼顶所问的数组的length是怎么得到的一个回答。同时,我也想说明,如果一个变量引用了这个数组,这个引用所代表的地址是指到第一个数组元素所在的地址,还是指到为内存头所在的地址,是和jvm实现相关的。甚至于内存头和其所对应的内存块是连续存放的,还是不连续存放的,也是与jvm实现相关的,java语言并不care这个。用引用这个概念,我可以屏蔽这些差异,而用地址,则太底层了,无法屏蔽。
      

  41.   


    栈空间有地址和空间, 堆里也有地址和空间!~ 
    很明显: 
    int[] a, b;   
    a = new int[100];     
    很明显,这经过了赋值运算的一个过程! 
    ----------
    楼主一直都是在陈述,一个问句都没有,何惑之有?提醒楼主多次了,不要用地址这个概念来考虑问题,用引用,这个是java里明确给出的概念。当然,引用最终是靠地址来实现的,但从概念上来说,我们把这个地址叫做引用。但从另一个角度想,目前的计算机需要用地址来表示引用,如果有另外一个体系结构的计算机,我可以完全不用地址而一样能表示引用。所以说,地址是与jvm实现相关的,而引用则是java语言自身的概念,独立于jvm。声明变量的作用是什么? >.  
    1.识别! 
    2.分配空间! 
    ----------
    你的这两句说的没错,变量说白了就是个“助记符”!没有什么特殊意义。我所强调的是:对于primary类型的来说,变量里面存的是;对于Object的子类(包括Object本身)来说,变量里存的是引用。我并不care变量本身的在哪里,是在堆还是在栈都没关系,我care的是变量里存的东西。new int[100] 结果是在堆上生成一个int数组的存储空间,这个空间可以存放100个int类型的,并且缺省的,这些都是0。如果改为 new String[100],则结果在堆上生成一个String数组的存储空间,这个空间可以存放100个String类型对象的引用,并且缺省的,这些引用都是null。这里是对数组的初始化,是java规范里要求的,不应该理解为普通意义上的赋值,因为并没有调用赋值操作。1个int需要4个字节来保存,但new int[100]并不是仅仅生成100*4个字节,还需要为管理这些内存多申请一小块(内存头),具体多大取决于虚拟机实现,用于对这100*4个字节的管理。这也是对楼顶所问的数组的length是怎么得到的一个回答。同时,我也想说明,如果一个变量引用了这个数组,这个引用所代表的地址是指到第一个数组元素所在的地址,还是指到为内存头所在的地址,是和jvm实现相关的。甚至于内存头和其所对应的内存块是连续存放的,还是不连续存放的,也是与jvm实现相关的,java语言并不care这个。用引用这个概念,我可以屏蔽这些差异,而用地址,则太底层了,无法屏蔽。
      

  42.   


    栈空间有地址和空间, 堆里也有地址和空间!~ 
    很明显: 
    int[] a, b;   
    a = new int[100];     
    很明显,这经过了赋值运算的一个过程! 
    ----------
    楼主一直都是在陈述,一个问句都没有,何惑之有?提醒楼主多次了,不要用地址这个概念来考虑问题,用引用,这个是java里明确给出的概念。当然,引用最终是靠地址来实现的,但从概念上来说,我们把这个地址叫做引用。但从另一个角度想,目前的计算机需要用地址来表示引用,如果有另外一个体系结构的计算机,我可以完全不用地址而一样能表示引用。所以说,地址是与jvm实现相关的,而引用则是java语言自身的概念,独立于jvm。声明变量的作用是什么? >.  
    1.识别! 
    2.分配空间! 
    ----------
    你的这两句说的没错,变量说白了就是个“助记符”!没有什么特殊意义。我所强调的是:对于primary类型的来说,变量里面存的是;对于Object的子类(包括Object本身)来说,变量里存的是引用。我并不care变量本身的在哪里,是在堆还是在栈都没关系,我care的是变量里存的东西。new int[100] 结果是在堆上生成一个int数组的存储空间,这个空间可以存放100个int类型的,并且缺省的,这些都是0。如果改为 new String[100],则结果在堆上生成一个String数组的存储空间,这个空间可以存放100个String类型对象的引用,并且缺省的,这些引用都是null。这里是对数组的初始化,是java规范里要求的,不应该理解为普通意义上的赋值,因为并没有调用赋值操作。1个int需要4个字节来保存,但new int[100]并不是仅仅生成100*4个字节,还需要为管理这些内存多申请一小块(内存头),具体多大取决于虚拟机实现,用于对这100*4个字节的管理。这也是对楼顶所问的数组的length是怎么得到的一个回答。同时,我也想说明,如果一个变量引用了这个数组,这个引用所代表的地址是指到第一个数组元素所在的地址,还是指到为内存头所在的地址,是和jvm实现相关的。甚至于内存头和其所对应的内存块是连续存放的,还是不连续存放的,也是与jvm实现相关的,java语言并不care这个。用引用这个概念,我可以屏蔽这些差异,而用地址,则太底层了,无法屏蔽。
      

  43.   

     第二个:     先说说39楼这个同志回答的吧!
    1、A[] a = new A[100];//已经分配空间了
    ,在stack中分配了空间存a;在hea中创建了一个新对象(Array类型),
    //
    这个对象是 A类型的!~不对,这个对象是Array类型的,里面能存100个引用(或者叫指向,分别指向一个A类型的对象) 
    可以存100个数据元素,并非要是A的对象,元素是任何类型的;不对,这里是定义了一个Array,里面的元素是A类型的,不是数组是A类型的,数组就是数组类型(Array)
      

  44.   

    int []a//你自己对照第二个去理解吧。这里只是声明了一个变量叫a,其值是一个元素为int的数组,
    或者说a引用了一个元素为int的数组。这个数组和a是两回事!假如代码如下: 你这句话说的是对的! 声明了一个变量a , 
    并在栈空间里分配了为int类型变量足够的空间! 
    这个是我的补充!~
    不对,stack中只为a分配了空间,这个a可以指向一个数组(里面存int),但现在这个数组还没有分配空间,所以a指向null,将来给数组分配空间也是在heap中分配,因为数组不是primitive类型。再补充查到的一个知识点: 
    变量名是不可变的, 也就是说它的地址是唯一的,分配了不可再改变!不对,例如:
    Dog d1 = new Dog();
    Dog d2 = new Dog();
    d1 = d2;  //d1的指向已经变了,现在指向后来创建的那个对象了因为变量是有生命周期的,出了大括号就不存在了,所以它的地址是在栈里的!
    出栈就消失了!~
    它的值究竟在不在栈里呢? > 不太清楚, 估计基本数据类型是在栈里的!

    变量在stack中还是在heap中,要看变量是 实例变量(instance variable)还是局部变量(local variable)
    instance variable 在heap中, local variable 在stack中
    实际上,stack中是按method出入stack的,先调用的method在下面,然后再调用的method在上边,最上边的method是当前运行的methed,local variable就分配在这个methed所占的空间中,当然也是在stack中了。当前的method运行完,弹出stack,这个method里面声明的变量也一起消失了。程序返回到stack中的下一个method继续运行。

    所以基本数据类型==是比较值!
    int a1 = 3;  int a2 = 4; //a1和a2里面存的就是3和4本身。
    Dog d1 = new Dog(); Dog d2 = new Dog(); //d1和d2里面分别存这两个独享的引用,这两个引用显然不同,比较结果就是false了。
    不知道你可否还能为 这句话 再做补充,因为"[]" 并没有解释到~!~
    第三个:
    int[] a, b; 
    a = new int[100]; //new  的 地址  肯定是在堆里了,  这点大家都不怀疑!
    这个时候 变量a 的地址是不可变的!~ 好,抛开地址不谈, 
    我们谈空间, 这个小块内存肯定是在堆里了!~ 到这里你看出点疑惑了吗?.. 请您把这里解释通!~~a在 stack中, new int[100]这个数组对象在heap中。建议楼主看下《head first in java》,里面说的非常清楚。