String对象的不变性和intern()方法

1.创建字符串的方式

//使用字符串常量
String str0 = "I Love U";
//使用常量表达式
String str1 = "I" + "Love U";
//使用new()运算
String str2 = new String("I Love U");

2.String对象的不变性

    String类是由final关键字修饰的,不能被继承,初始化后不能更改

String a = "I Love Java";
String b = "I" + "Love" + "Java";
String c = new String("I Love Java");
System.out.println(a == b); //true
System.out.println( a == c); //false
System.out.println(a.equals(c)); //true

在这里提一下equals()方法和的区别:
    比较的是地址,当且仅当基本类型的变量值相等或者引用类型的引用指向同一个对象才会返回true,有人可能有疑惑,不是说比较的是地址,为什么基本类型比较的是值?其实基础类型通过JVM初始化时生成其装箱对象的缓存,然后所有基本类型都被映射到这些缓存对象上,所以做出
相等的假象,因为实际上的确是同一个缓存对象,地址相同。但超过特定值就会失效,超过特定值的基本类型装箱对象是在堆生成,每次都会变动,这样地址不相同。
    equals()方法继承于java.lang.Object,对于具体的类,要重写equals()方法才能实现内容的比较,本质上还是
,例如String类:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            //这里value是储存字符串每一个字符的字符数组
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

    下面回到正题,为什么a == c是false而a.equals©就是true
String对象创建
    很明显引用指向的不是一个对象,地址不同,用“==”方法必然是返回false。
    另外,提一下new String(“I Love Java”)这个方法,会先在常量池中寻找"I Love Java",没有回在常量池中创建一个,然后堆中再创建一个常量池中此 "china” 对象的拷贝对象。

3.字符串常量池

    String使用private final char value[ ]实现字符串的存储,也就是说String创建对象之后不能够再次修改此对象中存储的字符串内容,因而String类型是不可变的(immutable),因而String类是线程安全的。
    其中字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享。

4.intern()方法

    首先来看下API文档的描述:
    public String intern()
    返回字符串对象的规范化表示形式。
    一个初始时为空的字符串池,它由类 String 私有地维护。
    当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
    它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true

String s = "Java";
String t = new String(s);
String l = new String("Java");

System.out.println(s == t.intern()); //true
System.out.println(t ==l); //false
System.out.println(t == l.intern()); //false
System.out.println(t.intern() == l.intern()); //true

不过,不能滥用intern()方法,如果数据了很大的话,反而影响性能,打个比方,调用intern()方法,一开始有点像对常量池先进行遍历,数据了一大遍历一次都要很长时间,更不用说几百万,几千万条数据了,所以请谨慎使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值