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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 杨兴庭 于 2013-7-10 22:17 编辑

关于常量池内部的变量的特点,例如String字符串,在视频上这个例子结果是懂了,但是想咨询下常量池内部常量的一些特点,以备后期学习用,求指教?
  1. class StringMethodDemo{
  2. public static void main(String args[]){
  3. String s1="abc";
  4. String s2=new String("abc");
  5. String s3="abc";
  6. System.out.println(s1==s2);
  7. System.out.println(s1==s3);
  8. }
  9. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1

查看全部评分

6 个回复

倒序浏览
是不可更改的,在编译初期就订好的,为方便快捷的引用,在多次引用到是不需要重复的创建变量。
回复 使用道具 举报
本帖最后由 toShareBeauty 于 2013-7-9 20:54 编辑

常量池,是每个已经加载的类在 jvm 的方法区中的一个逻辑分区,可以动态添加,常量池就是该类型所用常量的一个有序集合,包括直接常量和对其他类型、字段和方法的符号引用,符号引用在动态链接阶段修改为直接引用,其中直接常量只能存储 jvm 支持的数据类型,就是8种基本类型、引用类型(所有引用类型在jvm看来都是 reference 类型)、数组类型。每个字符串对象一定对应堆中的两个对象,一个是字符串对象,一个是字符串对应的 char[] 对象,两个字符串对象不一定有四个对象,所谓字符串保存在常量池,其实是这个 char[] 对象的引用保存在常量池,这个 char[] 对象还是保存在堆中。字符串类前面的 final 修饰词不是指字符串对象不能修改,其实是 String 对象不能被继承扩展,字符串对象不能不修改主要是加入常量池的 char[] 对象不能被修改,所以字符串对象一旦修改,首先是jvm在所有的常量池查找于修改后的字符串对应的 char[] 有没有一样的类容的,如果有,直接把这个 char[] 的引用赋给赋给字符串的成员变量,如果没有,就重新创建一个 char[] 对象,并且加入常量池。
  1. public class StringObjectDemo {

  2.         /**
  3.          * @param args
  4.          */
  5.         public static void main(String[] args) {
  6.                 // TODO Auto-generated method stub
  7.                 Object s1 = new String("Hello");
  8.                 Object s2 = new String("Hello");
  9.                 String s3 = new String("World");
  10.                
  11.                 if(s1 == s2) {
  12.                         System.out.println("s1 and s2 are ==");
  13.                 }else if (s1.equals(s2)) {
  14.                         System.out.println("s1 and s2 are equals()");
  15.                 }
  16.                  
  17.                 System.out.println("s1.hashcode:" + s1.hashCode());
  18.                 System.out.println("s2.hashcode:" + s2.hashCode());
  19.                 System.out.println("s3.hashcode:" + s3.hashCode());
  20.                
  21.                 s2 = s1 + s3;
  22.                 s1 = s1 + s3;
  23.                 System.out.println("s1.hashcode:" + s1.hashCode());
  24.                 System.out.println("s2.hashcode:" + s2.hashCode());
  25.                
  26.                 System.out.println(new StringObject().creatStringObject().hashCode());
  27.         }
  28. }

  29. class StringObject{
  30.         public String creatStringObject(){
  31.                 return new String("HelloWorld");
  32.         }
  33. }
复制代码
因为 String 的 hashcode 已经重写为 String 对应的 char[] 对象的 hashcode,(从源码来看我这个地方说得有错啦,所有后面的结论也是错误的),所以从这个程序打印的 hashcode 值可以知道 char[] 对象的个数,我打印的结果是:

最后的结果说明,常量池是可以动态添加的,因为 "Hello world" 这个字符串对应的字符数组常量明显是程序运行过程中得出的,而且不同的类还可以共用一个 char[] 对象。

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1

查看全部评分

回复 使用道具 举报
toShareBeauty 发表于 2013-7-9 15:22
常量池,是每个已经加载的类在 jvm 的方法区中的一个逻辑分区,可以动态添加,常量池就是该类型所用常量的 ...

O(∩_∩)O谢谢
回复 使用道具 举报
toShareBeauty 发表于 2013-7-9 15:22
常量池,是每个已经加载的类在 jvm 的方法区中的一个逻辑分区,可以动态添加,常量池就是该类型所用常量的 ...

s1和s2的hashcode是相等的,为啥s1==s2不成立?
回复 使用道具 举报
本帖最后由 toShareBeauty 于 2013-7-9 21:29 编辑
阿凡提不买驴 发表于 2013-7-9 20:11
s1和s2的hashcode是相等的,为啥s1==s2不成立?

== 运算符是当两个引用指向同一个对象的时候才会返回 true;前面其实说过,String 类型的 hashcode 函数已经被重写,不是 Object 的 hashcode 而返回的是 String 内部成员 char[] 对象的中所有字符按照 hashcode 算法计算的 hashcode 值(注意:上个回答我说错了,我以为返回的是 char 对象的 hashcode 值,i’m very sorry),这个值只能保证字符串的内容是不是一样,不能表示对象的存储关系,就算因为 flyweight 模式的关系 s1 s2 内部的 char[] 是同一个对象(从我调试结果来看其实不同)。但是 s1 s2 对应的 String 对象却不是同一个。
  1.     /**
  2.      * Returns a hash code for this string. The hash code for a
  3.      * <code>String</code> object is computed as
  4.      * <blockquote><pre>
  5.      * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
  6.      * </pre></blockquote>
  7.      * using <code>int</code> arithmetic, where <code>s[i]</code> is the
  8.      * <i>i</i>th character of the string, <code>n</code> is the length of
  9.      * the string, and <code>^</code> indicates exponentiation.
  10.      * (The hash value of the empty string is zero.)
  11.      *
  12.      * @return  a hash code value for this object.
  13.      */
  14.     public int hashCode() {
  15.         int h = hash;
  16.         if (h == 0 && value.length > 0) {
  17.             char val[] = value;

  18.             for (int i = 0; i < value.length; i++) {
  19.                 h = 31 * h + val[i];
  20.             }
  21.             hash = h;
  22.         }
  23.         return h;
  24.     }
复制代码
  1.     /** The value is used for character storage. */
  2.     private final char value[];

  3.     /** Cache the hash code for the string */
  4.     private int hash; // Default to 0
复制代码
上面是 String 的源码 其中
private final char value[];  
这个地方也足以说明我前面的结论,String 对象不可以修改,是因为有个 final 的 char[] 引用类型的成员变量。
调试过程中 s1 s2 中的数组引用:




回复 使用道具 举报
toShareBeauty 发表于 2013-7-9 20:31
== 运算符是当两个引用指向同一个对象的时候才会返回 true;前面其实说过,String 类型的 hashcode 函数已 ...

好的,懂了,O(∩_∩)O谢谢哥们
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马