黑马程序员技术交流社区

标题: 有关String变量地址值的两个问题! [打印本页]

作者: 贾永长    时间: 2013-7-2 08:58
标题: 有关String变量地址值的两个问题!
本帖最后由 孙百鑫 于 2013-7-3 21:25 编辑

第一个问题:两个Strings类型变量都初始化为同一个值,为什么内存地址值会一样?
第二个问题:怎样打印输出String类型变量的地址值啊?
示例代码:
  1. class Demo7
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 String s1 = "abcd";
  6.                 String s2 = "abcd";        //s1和s2应该是开辟两个空间啊 地址值也该不一样啊
  7.                 if(s1==s2)
  8.                         System.out.println("s1和s2的地址值相同");
  9.                 else
  10.                         System.out.println("s1和s2的地址值不同");
  11.         }
  12. }
复制代码
运行结果:
  1. s1和s2的地址值相同
复制代码

作者: 杜光    时间: 2013-7-2 09:07
  1. class Demo
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 String s1 = "abcd";
  6.                 String s2 = "abc";        //s1和s2应该是开辟两个空间啊 地址值也该不一样啊
  7.                 if(s1==s2)
  8.                         System.out.println("s1和s2的地址值相同");
  9.                 else
  10.                         System.out.println("s1和s2的地址值不同");
  11.         }
  12. }
复制代码
  1. 输出结果:s1和s2的地址值不同
复制代码
毕老师基础视频里面,我记的好像提到过,因为s1如果在堆内存中创建了一个字符串,s2创建的字符串和s1中的一样的话,s2指向的堆内存的地址和s1中是同一个,而不再开辟一个空间

作者: uuom    时间: 2013-7-2 09:21
创建字符串对象可以有两种方式:
   1)String str1 = new String("abc");     
   2)String str2 = "abc";   
   虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。
   对于第一种(用new关键词创建的),jvm会马上在堆中创建一个String对象,然后将该对象的引用返回给用户。
   对于第二种,jvm首先会在内部维护的strings pool中通过String的 equels() 方法查找是对象池中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。

我正看到String类型,这些是从我参考书上了解的。
作者: 贾永长    时间: 2013-7-2 09:28
杜光 发表于 2013-7-2 09:07
毕老师基础视频里面,我记的好像提到过,因为s1如果在堆内存中创建了一个字符串,s2创建的字符串和s1中的一 ...

哦,原来如此!谢啦!那。。。
1:怎样打印输出String类型变量的地址值啊?
2:“创建的内容一样的话,就指向同一个地址值” 这是String型变量的特性吗?--------》比如:都是引用型变量的int数组就不一样,见如下代码:
代码:
  1.                 int[] x = {1,2,3};
  2.                 int[] y = {1,2,3};
  3.                 System.out.println(x);
  4.                 System.out.println(y);
复制代码
运行结果:
  1. [I@1fb8ee3
  2. [I@61de33
复制代码

作者: 贾永长    时间: 2013-7-2 09:32
uuom 发表于 2013-7-2 09:21
创建字符串对象可以有两种方式:
   1)String str1 = new String("abc");     
   2)String str2 = "abc" ...

好详细啊!原理这下明白了!谢了哈!
1:怎样打印输出String类型变量的地址值啊?
2:那这个原理是String特有的吗?--------》比如:都是引用型变量的int数组就不一样,见如下代码:
代码:
  1.                 int[] x = {1,2,3};
  2.                 int[] y = {1,2,3};
  3.                 System.out.println(x);
  4.                 System.out.println(y);
复制代码
运行结果:
  1. [I@de6ced
  2. [I@c17164
复制代码

作者: uuom    时间: 2013-7-2 10:51
贾永长 发表于 2013-7-2 09:32
好详细啊!原理这下明白了!谢了哈!
1:怎样打印输出String类型变量的地址值啊?
2:那这个原理是String ...

1) 可以利用它的hash值。hashCode默认返回的是虚拟机地址,不可能是实际的内存地址,java也不会允许。
但是可以认为他是Java对象的内存地址。
    对于字符串可以:System.out.println(System.identityHashCode(b));
   
    如果只是用于判断两个String对象值和地址是否相等,可以用分别用 String的equal()方法 和  “==”



2)
“创建的内容一样的话,就指向同一个地址值” 这是String型变量的特性吗?
  这句话就不对。 在JVM的工作过程中,会创建一片的内存空间专门存入String对象,这片内存空间叫做String池。
  a)当对象是String str = new String(“abc”)生成的而不是直接String str = “abc”这样赋值生成都会在内存中开辟新的地址的,不管其值是否相等,地址一定不同。
  b)如果你不是明确地new一个String对象,例如:String str = “abc”;  Java对于String对象的保存默认的是会把新生成的String 对象放到一个缓冲区(即String池)中,然后每次判断String池中是否已经有了这个对象,如果有了,那么后建立的同样字符值的String对象也会指向最初建立是该字符值对象的地址。否则创建新的String对象,放到String池里面。
只有 b)这种情况才会有其值相等,由于是同一个对象,它们的地址也会相同。

作者: 曹德君    时间: 2013-7-2 12:15
是String特有,高新技术里面会学到是享元设计模式。是为了优化内存效率才这么做的.Integer对象也用了这个思路。
作者: 贾永长    时间: 2013-7-2 12:17
uuom 发表于 2013-7-2 10:51
1) 可以利用它的hash值。hashCode默认返回的是虚拟机地址,不可能是实际的内存地址,java也不会允许。
但 ...

OK!原理分析的真到位!高人啊!Thank油了哈!{:soso_e181:}{:soso_e156:}
赶紧保存下来!{:soso_e130:}

作者: uuom    时间: 2013-7-2 12:56
贾永长 发表于 2013-7-2 12:17
OK!原理分析的真到位!高人啊!Thank油了哈!
赶紧保存下来!
...

囧。我才不是高人。自学到这里了。又参考资料才回答的。加油。奋斗一个暑假希望能进24期




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2