String StringBuffer,StringBuilder 原理


String,StringBuffer,StringBuilder 是经常使用的,了解其原理十分重要


查看String源码

[java]  view plain  copy
  1. public final class String  
  2.     implements java.io.Serializable, Comparable<String>, CharSequence {  
  3.     /** The value is used for character storage. */  
  4.     private final char value[];  
  5.   
  6.     /** Cache the hash code for the string */  
  7.     private int hash; // Default to 0  
  8.   
  9.     /** use serialVersionUID from JDK 1.0.2 for interoperability */  
  10.     private static final long serialVersionUID = -6849794470754667710L;  
  11.   
  12.    }  

发现String底层的数据结构是 字符数组 char[]

其次 常用的String 操作:

1.创建对象

[java]  view plain  copy
  1. private static void testString() {  
  2.         //查看下 str1 str2区别  
  3.         String str1 = "hello world";  
  4.         String str2 = new String("hello world");  
  5.         String str3 =  new String("hello world");  
  6.         String str4= "hello world";  
  7.         System.out.println(str1==str2); //false  
  8.         System.out.println(str1== str3); //false  
  9.         System.out.println(str2== str3); //true  
  10.         System.out.println(str1==str4); //true  
  11.           
  12.     }  


String str ="hello world" 是存在字符串常量区的 这歌可以看到 str1 str2 是完全一样的  这个字符串常量区,在JDK1,8之前存放的是永久区 PermGen,JDK1.8之后又个metaSpace进行存放。


而String str = new String("hello world") 存放的是堆 区, 每次new 都新建一个对象 可以如下验证


验证字符串常量存放

[java]  view plain  copy
  1. private static void testStringPermgen() {  
  2.             String str = "abc";    
  3.             char[] array = {'a''b''c'};    
  4.             String str2 = new String(array);    
  5.             //使用intern()将str2字符串内容放入常量池    
  6.             str2 = str2.intern();    
  7.             //这个比較用来说明字符串字面常量和我们使用intern处理后的字符串是在同一个地方    
  8.             System.out.println(str == str2);    
  9.             //那好,以下我们就拼命的intern吧    
  10.             ArrayList<String> list = new ArrayList<String>();    
  11.             for (int i = 0; i < 10000000; i++) {    
  12.                 String temp = String.valueOf(i).intern();    
  13.                 list.add(temp);    
  14.             }    


验证对象 堆中存放



常用方法有 replace  substring  concat

replace 先找到第一个和新替换值相同的位置,将前面的值不相同的先进行for循环赋值

再用while循环判断数组中的值是否oldchar 一样的有的话,替换成新值,没有的还有原来的值

[java]  view plain  copy
  1. public String replace(char oldChar, char newChar) {  
  2.         if (oldChar != newChar) {  
  3.             int len = value.length;  
  4.             int i = -1;  
  5.             char[] val = value; /* avoid getfield opcode */  
  6.   
  7.             while (++i < len) {  
  8.                 if (val[i] == oldChar) {  
  9.                     break;  
  10.                 }  
  11.             }  
  12.             if (i < len) {  
  13.                 char buf[] = new char[len];  
  14.                 for (int j = 0; j < i; j++) {  
  15.                     buf[j] = val[j];  
  16.                 }  
  17.                 while (i < len) {  
  18.                     char c = val[i];  
  19.                     buf[i] = (c == oldChar) ? newChar : c;  
  20.                     i++;  
  21.                 }  
  22.                 return new String(buf, true);  
  23.             }  
  24.         }  
  25.         return this;  
  26.     }  


再次看substring方法 SubString方法判断截取是否合法之后,用数组 ArrayCopy的方式进行生成了String


[java]  view plain  copy
  1. public String substring(int beginIndex, int endIndex) {  
  2.         if (beginIndex < 0) {  
  3.             throw new StringIndexOutOfBoundsException(beginIndex);  
  4.         }  
  5.         if (endIndex > value.length) {  
  6.             throw new StringIndexOutOfBoundsException(endIndex);  
  7.         }  
  8.         int subLen = endIndex - beginIndex;  
  9.         if (subLen < 0) {  
  10.             throw new StringIndexOutOfBoundsException(subLen);  
  11.         }  
  12.         return ((beginIndex == 0) && (endIndex == value.length)) ? this  
  13.                 : new String(value, beginIndex, subLen);  
  14.     }  
[java]  view plain  copy
  1. public String(char value[], int offset, int count) {  
  2.         if (offset < 0) {  
  3.             throw new StringIndexOutOfBoundsException(offset);  
  4.         }  
  5.         if (count <= 0) {  
  6.             if (count < 0) {  
  7.                 throw new StringIndexOutOfBoundsException(count);  
  8.             }  
  9.             if (offset <= value.length) {  
  10.                 this.value = "".value;  
  11.                 return;  
  12.             }  
  13.         }  
  14.         // Note: offset or count might be near -1>>>1.  
  15.         if (offset > value.length - count) {  
  16.             throw new StringIndexOutOfBoundsException(offset + count);  
  17.         }  
  18.         this.value = Arrays.copyOfRange(value, offset, offset+count);  
  19.     }  


再看concat方法

[java]  view plain  copy
  1. public String concat(String str) {  
  2.         int otherLen = str.length();  
  3.         if (otherLen == 0) {  
  4.             return this;  
  5.         }  
  6.         int len = value.length;  
  7.         char buf[] = Arrays.copyOf(value, len + otherLen);  
  8.         str.getChars(buf, len);  
  9.         return new String(buf, true);  
  10.     }  


对String相关的操作都不会影响到原来的对象,相关的操作,都会产生新对象

[java]  view plain  copy
  1. javap -c命令反编译生成的class文件进行验证。  


StringBuilder 


比较常用的是append方法

[java]  view plain  copy
  1. @Override  
  2.     public StringBuilder append(Object obj) {  
  3.         return append(String.valueOf(obj));  
  4.     }  
  5.   
  6.     @Override  
  7.     public StringBuilder append(String str) {  
  8.         super.append(str);  
  9.         return this;  
  10.     }  


有个问题:

[java]  view plain  copy
  1. string+=”hello”的操作  
是怎么干的。实际上是哟如下三个操作:

[java]  view plain  copy
  1. StringBuilder str = new StringBuilder(string);  
  2.   
  3. str.append(“hello”);  
  4.   
  5. str.toString();  

String +="hello“每次都会new 一个String,会造成一定的资源浪费,而对于StringBuilder 来说每次append 都是在原有基础上增加的相对来说 比String+= 这个方式少用了很多内存资源,因此推荐StringBuilder 代替 String+= 这个方式, 但是如果有多次append会影响效率的

如String str = “hello”+ “world”的效率就比 StringBuilder st  = new StringBuilder().append(“hello”).append(“world”)要高。

StringBuilder在一次+时候 资源,还是性能相对来说都比较高

问题来了StringBuilder 对String类进行了一定优化,为啥还要StringBuffer?

这个就是线程安全的问题了

append方法

[java]  view plain  copy
  1. @Override  
  2.    public synchronized StringBuffer append(String str) {  
  3.        toStringCache = null;  
  4.        super.append(str);  
  5.        return this;  
  6.    }  


[java]  view plain  copy
  1. @Override  
  2. public synchronized StringBuffer replace(int start, int end, String str) {  
  3.     toStringCache = null;  
  4.     super.replace(start, end, str);  
  5.     return this;  
  6. }  
  7.   
  8. /** 
  9.  * @throws StringIndexOutOfBoundsException {@inheritDoc} 
  10.  * @since      1.2 
  11.  */  
  12. @Override  
  13. public synchronized String substring(int start) {  
  14.     return substring(start, count);  
  15. }  

String StringBuilder StringBuffer 都是不可继承的都是final的

StringBuffer 方法大多都加了synchronized ,线程安全。


转载于:https://blog.csdn.net/wangming520liwei/article/details/79809253

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值