剖析String

Java String池与内存管理

 

  • 栈(stack):主要保存基本类型(或者叫内置类型)(char、byte、short、int、long、float、double、boolean)和对象的引用,数据可以共享,速度仅次于寄存器(register),快于堆。
  • 堆(heap):用于存储对象。 
  • String池(pool) :JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象; 并且可以被共享使用,因此它提高了效率。
public static void main(String[] args) {  
        /** 
         * 情景一:字符串池 
         * JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象; 
         * 并且可以被共享使用,因此它提高了效率。 
         * 由于String类是final的,它的值一经创建就不可改变。 
         * 字符串池由String类维护,我们可以调用intern()方法来访问字符串池。  
         */  
        String s1 = "abc";     
        //↑ 在字符串池创建了一个对象  
        String s2 = "abc";     
        //↑ 字符串pool已经存在对象“abc”(共享),所以创建0个对象,累计创建一个对象  
        System.out.println("s1 == s2 : "+(s1==s2));    
        //↑ true 指向同一个对象,  
        System.out.println("s1.equals(s2) : " + (s1.equals(s2)));    
        //↑ true  值相等  
        //↑------------------------------------------------------over  
        /** 
         * 情景二:关于new String("") 
         *  
         */  
        String s3 = new String("abc");  
        //↑ 创建了两个对象,一个存放在字符串池中,一个存在与堆区中;  
        //↑ 还有一个对象引用s3存放在栈中  
        String s4 = new String("abc");  
        //↑ 字符串池中已经存在“abc”对象,所以只在堆中创建了一个对象  
        System.out.println("s3 == s4 : "+(s3==s4));  
        //↑false   s3和s4栈区的地址不同,指向堆区的不同地址;  
        System.out.println("s3.equals(s4) : "+(s3.equals(s4)));  
        //↑true  s3和s4的值相同  
        //↑------------------------------------------------------over  
        /** 
         * 情景三:  
         * 由于常量的值在编译的时候就被确定(优化)了。 
         * 在这里,"ab"和"cd"都是常量,因此变量str3的值在编译时就可以确定。 
         * 这行代码编译后的效果等同于: String str3 = "abcd"; 
         */  
        String str1 = "ab" + "cd";  //1个对象  
        String str11 = "abcd";   
        System.out.println("str1 = str11 : "+ (str1 == str11));  
        //↑------------------------------------------------------over  
        /** 
         * 情景四:  
         * 局部变量str2,str3存储的是存储两个拘留字符串对象(intern字符串对象)的地址。 
         *  
         * 第三行代码原理(str2+str3): 
         * 运行期JVM首先会在堆中创建一个StringBuilder类, 
         * 同时用str2指向的拘留字符串对象完成初始化, 
         * 然后调用append方法完成对str3所指向的拘留字符串的合并, 
         * 接着调用StringBuilder的toString()方法在堆中创建一个String对象, 
         * 最后将刚生成的String对象的堆地址存放在局部变量str4中。 
         *  
         * 而str5存储的是字符串池中"abcd"所对应的拘留字符串对象的地址。 
         * str4与str5地址当然不一样了。 
         *  
         * 内存中实际上有五个字符串对象: 
         *       三个拘留字符串对象、一个String对象和一个StringBuilder对象。 
         */  
        String str2 = "ab";  //1个对象  
        String str3 = "cd";  //1个对象                                         
        String str4 = str2+str3;                                        
        String str5 = "abcd";    
        System.out.println("str4 = str5 : " + (str4==str5)); // false  
        //↑------------------------------------------------------over  
        /** 
         * 情景五: 
         *  JAVA编译器对string + 基本类型/常量 是当成常量表达式直接求值来优化的。 
         *  运行期的两个string相加,会产生新的对象的,存储在堆(heap)中 
         */  
        String str6 = "b";  
        String str7 = "a" + str6;  
        String str67 = "ab";  
        System.out.println("str7 = str67 : "+ (str7 == str67));  
        //↑str6为变量,在运行期才会被解析。  
        final String str8 = "b";  
        String str9 = "a" + str8;  
        String str89 = "ab";  
        System.out.println("str9 = str89 : "+ (str9 == str89));  
        //↑str8为常量变量,编译期会被优化  
        //↑------------------------------------------------------over  
    }  

 总结:

1、当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。

2、Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。 

3、使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。 

4、使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。

String 类是 Java 中最常用的类之一,用于表示字符串对象。下面是对 String 类的源码剖析: 1. String 类的定义: ```java public final class String implements java.io.Serializable, Comparable<String>, CharSequence { // ... } ``` String 类是 final 类,无法被继承,实现了 Serializable 接口,以支持对象的序列化操作。它还实现了 Comparable 接口,用于字符串的比较,以及 CharSequence 接口,提供了对字符序列的一般读取方法。 2. 字段: ```java private final char value[]; private final int offset; private final int count; private int hash; ``` - value: 用于存储字符串的字符数组。 - offset: 字符数组中有效字符的起始位置。 - count: 字符数组中有效字符的数量。 - hash: 字符串的哈希值,用于加速字符串比较操作。 3. 构造函数: String 类提供了多个构造函数,用于创建字符串对象。其中包括使用字符数组、字节数组、字符串、StringBuffer 等作为参数的构造函数。 4. 方法: - length(): 返回字符串的长度。 - charAt(int index): 返回指定索引位置的字符。 - substring(int beginIndex): 返回从指定索引开始到字符串末尾的子字符串。 - indexOf(int ch): 返回指定字符在字符串中第一次出现的位置。 - equals(Object anObject): 比较字符串与指定对象是否相等。 - compareTo(String anotherString): 按字典顺序比较两个字符串。 - concat(String str): 将指定字符串连接到此字符串的末尾。 - toUpperCase(): 将字符串转换为大写。 - toLowerCase(): 将字符串转换为小写。 - trim(): 返回一个去除了首尾空格的字符串。 这些只是 String 类的一部分方法,还有很多其他方法可以使用。String 类还提供了不少静态方法,如 valueOf、format 等,用于字符串的转换和格式化操作。通过这些方法,我们可以方便地操作和处理字符串。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值