对String的总结

1 Java中常量池的区分
(1)全局字符串池(string pool)
—全局字符串池里的内容是在类加载完成,经过验证、准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中。
—字符串常量池中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间中存放的。
—在HotSpot VM里实现string pool功能的是一个StringTable类,它是一个哈希表,里面存的是驻留字符串(也即我们常说的用双引号括起来的字符串)的引用,也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了“驻留字符串”的身份。这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。
—优点:避免了相同内容的字符串的创建,节省了内存省去了创建相同字符串的时间,同时提升了性能。
(2)class文件常量池
—用于存放编译期生成的各种字面量和符号引用。
—字面量:比较接近于java语言层面的常量概念,如文本字符串、被声明为final的常量值等。
—符号引用:以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。一般包含下面三类常量:
· 类和接口的全限定名
· 字段的名称和描述符
· 方法的名称和描述符
—常量池中每一项常量都是一个表,一共有十四种。
(3)运行时常量池
—运行时常量池是方法区的一部分,当类加载到内存后,JVM就会将class常量池中的内容存放到运行时常量池中。
—运行时常量池是每个类私有的。
—一般来说,class常量池中不仅存放对象的符号引用,还会把解析后的直接引用也存储在运行时常量池中。而在解析的过程中,会去查询全局字符串池,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的。

2 String类的特点
—String类初始化后是不可变的。
—String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。
—String类用final修饰的原因:
· 安全性:由于String类不可变,所以也就不会被修改,这就避免了多线程竞争的线程安全问题。
· 效率:String类在程序中出现的频率比较高,为了避免安全隐患,在它每次出现时都需要用final来修饰,如果使用的不好,会出现很明显的性能问题,所以干脆做成final类的,放在常量池实现数据共享,节省资源,提高效率,可以在JVM里做很多优化。
—String类其实是通过字符数组来保存字符串的。
—String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何改变操作都会生成新的对象。

3 字符串的创建
​ —创建String对象的方法最常见的有两种:
· 使用String对象的构造器显式创建,例如:String str = new String(“Hello”)。运行该语句时如果当前string pool中不存在值为"Hello"的字符串对象的引用,则会在Java堆中生成两个实例。一个是"Hello"的实例对象,并且在字符串常量池中保存了对该实例对象的引用;还有一个是new出来的值为"Hello"的实例对象。如果当前string pool中已经存在一个等于此String对象的字符串的引用,则只会在Java堆中生成一个新new出来的实例对象。并且无论是哪种情况,引用变量str都会指向那个新new出来的实例对象。
· 通过双引号方式直接创建,例如:String str = “Hello”。这条语句会查找常量池中是否已经存在"Hello"对象的引用,如果已经存在,则会将该引用复制并返回;否则,会在Java堆中创建一个新的对象并将其引用放入string pool 中并返回该引用。
—使用只包含常量的字符串连接符创建的也是常量,并且编译器会对其进行优化。如String str = “ab”+“cd”,这条语句编译器会对其进行优化,使得最终只有一个字符串常量"abcd"存入string pool中。
—对于使用包含变量的字符串连接符创建的对象,它所产生的新对象不会被存入string pool中。

4 String的intern()方法
​ —是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串的引用,则将池中的这个引用复制并返回;否则,将此String对象的字符串引用添加到常量池中,并且返回此String对象的引用。
—在JDK 1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代这个字符串实例的引用。
—在JDK 1.7及以后,intern()方法不会再复制实例,只是在常量池中记录首次出现的实例引用。

5 String的“==”和“equals"
—对于String类型的变量,”==“比较的是所指向的对象的地址,也即是否指向同一个对象。
—在Object类中,equals方法是用来比较两个对象的引用是否相等,也即是否指向同一个对象;而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的内容是否相等。

6 String、StringBuilder、StringBuffer的区别
​ —可变与不可变:String是不可变字符串对象;StringBuilder和StringBuffer是可变字符串对象,其内部的字符数组的长度可变。
—是否线程安全:String中的对象是不可变的,因此一定是线程安全的;StringBuffer和StringBuilder中的方法和功能基本等价,只是StringBuffer中的方法大都采用了synchronized关键字进行同步,因此,StringBuffer是线程安全的,而StringBuilder是非线程安全的。
—执行效率:一般来说,三者的执行效率的关系为:StringBuilder>StringBuffer>String。
—适用场合:
· String:适用于少量的字符串操作的情况。
· StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况。
· StringBuffer:适用于多线程下在字符缓冲区进行大量操作的情况。

7 String的compareTo()方法
​ —该方法是按照字典顺序来比较两个字符串。比较是基于字符串中各个字符的Unicode值。
—按字典顺序将此String对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此String对象位于参数字符串之前,则比较结果为一个负整数;如果按字典顺序此String对象位与参数字符串之后,则比较结果为一个正整数;如果两个字符串相等,则返回0。
—比较规则:
· 首先比较两个字符串的长度,比较在较小的长度内,两者是否相等。
· 如果不相等,则直接返回该位置字符的ASCII码相减后的值。
· 如果各位置都相等,则返回两个字符串长度的差值。

 public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值