常量池。。。。

jdk1.7之前放在方法区,1.7之后放在堆中。

常量池在java用于保存在编译器已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java" 这种申明方式;当然也可以扩充,故认为常量池是jvm的一块特殊的内存空间。

在Java程序中,有很多东西是永恒的,不会在运行过程中变化。比如一个类的名字,一个类字段的名字/所属类型,一个类方法的名字/返回类型/参数名与所属类型,一个常量,还有在程序中出现的大量的字面值。

比如下面这段代码中蓝色部分:

public class ClassTest {

    private String items = "我们";

    private final int iteml = 100;

    public void setItemS(String param) {...}

}

java常量池技术

java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间。String类也实现了常量池的技术,同样的,大部分包装类也实现了常量池的技术,具体百度。以下用String做说明。

测试代码如下:

public class Test {

    public static void main(String[] args) {

        // s1,s2分别位于栈中,指向堆中不同的空间

        String s1 = new String("hello");

        String s2 = new String("hello");

        System.out.println(s1 == s2); // 输出false

        // s3,s4位于池中同一空间

        String s3 = "hello";

        String s4 = "hello";

        System.out.println(s3 == s4); // 输出true

    }

}

用new String() 创建的字符串不是常量,不能再编译器就确定,所以new String() 创建的字符串不放入常量池中,他们有自己的地址空间。

String对象的不变性机制会使修改String字符串时,产生大量的对象,因为每次改变字符串,都会生成一个新的String对象。java为了更有效的使用内存,常量池在编译器遇见String字符串时,它会检查该池内是否已经存在相同的字符串,如果找到,就把新变量的引用指向现有的字符串对象,不创建任何新的String常量对象,没找到则创建新的对象。所以对一个字符串对象的任何修改,都会产生一个新的字符串对象,原来的依然存在,等待垃圾回收。

String a = "123456";
String b = "123" + "456";
String c = "123" + new String("456");
System.out.println(a == b); // true
System.out.println(b == c); // false

我对于以上代码的理解:

a先去常量池中找"123456",没找到,于是在常量池中创建了"123456"。而b的申明方式相当于"123"先于"456"拼接得到"123456",然后b去常量池中找"123456",找到了,于是b指向常量池中的"123456"。而c的申明方式,相当于在堆中创建了新对象,他不会去常量池中寻找,c会指向堆中其对应的内存空间。因此,a、b指向的是同一块空间,而b、c指向的是两块不同的空间。

再说说String类中的intern()方法。

String a = new String("java");
String b = a.intern();
String c = "java";
System.out.println(a); // java
System.out.println(b); // java
System.out.println(a == b); // false
System.out.println(a.intern() == b); // true
System.out.println(c == b); // true
System.out.println(c == a); // false

intern()方法相当于在常量池中创建一个对象,然后将引用指向该对象。因此b、c指向的是常量池中的同一块地方。而a指向的则是堆中的一块内存。故出现以上结果。

不要使用intern方法了,就是一个**方法。看以下的(jdk1.8):

String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1); // true
        
String str3 = new StringBuilder("he").append("hehe").toString();
System.out.println(str3.intern() == str3); // true
        
String a = "jdk";
String str4 = new StringBuilder("j").append("dk").toString();
System.out.println(str4.intern() == str4); // false
        
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == "java"); // true
System.out.println(str2.intern() == str2); // false
System.out.println(str2 == "java"); // false
        
System.out.println("*****************");
        
String str5 = new String("heihei"); 
System.out.println(str5.intern() == str5); // false
System.out.println(str5.intern() == "heihei"); // true
        
String str6 = "heihei";
System.out.println(str5 == str6); // false
System.out.println(str5.intern() == str6); // true
        
String str7 = new String("java");
System.out.println(str7.intern() == str7); // false
System.out.println(str7.intern() == "java"); // true

这个咋说的,1.7以后intern方法会先查看常量池是否存在该字符串,不存在的话,会将该字符串的引用扔进去。。。而不是将整个字符串扔进去。。。至于"java"这个字符串,jdk可能默认会在常量池里创建

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值