你听说过吗?CharSequence家族之String三剑客[Sting-StringBuffer-StringBuilder]的进制奇缘!

你听说过吗?CharSequence家族之String三剑客的[Sting-StringBuffer-StringBuilder]的进制奇缘!


1.String

1.1源码分析
1.1.1 String对象的实例化
	//直接使用字符串字面量进行赋值
	String str = "四原色";
	
	//使用intern()方法实例化String对象:
	//创建对象前会从字符串常量池中查询当前字符串是否存在,
	//如果存在,就直接返回当前字符串;
	//如果不存在就会将当前字符串放入常量池中,之后再返回。
	String str_inner = new String("四原色").intern();
	
	//无参构造,构造一个空字符串对象,值为null,不是"null"
	String str_noprimary = new String();
	
	//通过字符串数组构造
	char []chars = ['a','b','c'];
	String str_chars = new String(chars);
	
	//通过指定长度字符数组构造,从指定索引开始的指定长度
	String str_charsAsSize = new String(chars,0,1);
	
	//使用字符串字面量实例化字符串对象
	String str_chars_value = new String("四原色");
	
	//通过字节数组实例化
	byte []bytes = [1,2,3,4,5];
	String str_bytes = new String(bytes);
	
	//通过指定长度字节数组构造,从指定索引开始的指定长度
	String str_bytes_value = new String(bytes,2,3);
	    
	String str_bytes_sharsetStart = new String(bytes,String charsetName);
	
	String str_bytes_sub_sharsetStart = new String(byte[] bytes,
		int offset,
		int lentth,
		String charsetName);
	
	String str_stringBuffer = new String(StringBuffer buffer);
	
	String str_stringBuilder = new String(StringBuilder builder);
1.1.2常用方法
	String str = "四原色";
	
	//获取字符串长度
	int len = str.length(); 
	
	//字符串连接
	str.concat("666");
	str = "abc" + "cde";
	
	//从一个字符组截取一个字符
	char starChar = str.charAt(0);
	
	//获取子串,从start下标到最后一个。
	String subStar = str.subString(1);
	
	//获取子串,从start下标到最后一个,到end结束,不包括end。
	String subStarEnd = str.subString(02);
	
	//到一个字符数组
	char []chars = str.toCharArray(); 
	
	//到一个字节数组
	byte []bytes = str.getBytes();
	
	//指定的字符集,到一个字节数组
	String charsetName = "666";
	byte []bytesAsCharset = str.getByates(charsetName); 
	
	//放置到指定字符数组,
	//把str的第0个索引值开始到第1个索引值插入到新字符数组0索引位置
	char []target = ['1','a','c'];
	str.getChars(0,1,target,0);
	
	//将字符串中的出现的字母转为大写
	"abc".toUpperCase();
	
	//将字符串中的出现的字母转为小写
	"ABC".toLowerCase(); 
	    
	//去掉空格
	str.trim() ;
	
	//字符替换,将字符串str中的字符'6'替换为'5'
	String new_str = str.replace('6','5');
	
	//字符串替换,使用正则表达式regex替换指定格式字符串为新值replacement
	String regex = "[a-z]";
	String replacement = "A";
	String new_strAll = str.replaceAll(regex,replacement);
1.1.3 String源码分析
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence 
    {...}
  1. String类被final关键字修饰,不能被继承,它的成员方法都默认为final方法;字符串一旦创建就不能再修改,当对String进行变更时将在字符串常量池中产生新的字符串,即批量对字符串的处理是产生的内存消耗是非常大的.

  2. String类实现了Serializable、CharSequence、 Comparable接口.

  3. String实例的值是通过字符数组实现字符串存储的.

1.1.4 编译器对String的优化
  1. 对+字符串连接的优化:

    使用"+"连接字符串对象时,会创建一个StringBuilder()对象,即JVM会隐式创建StringBuilder对象,并调用append()方法将数据拼接,最后调用toString()方法返回拼接好的字符串。

	String str = "四原色"+ "666";
	
	String str = new StringBuilder("四原色").append("666").toString();
  1. 对编译器确定的字符串常量进行优化:

    当"+“两端均为编译期确定的字符串常量时,编译器会进行相应的优化,直接将两个字符串常量拼接好,此时字符串常量池中将存在的字符串常量是“四原色666”,而非"四原色"和"666”.

	System.out.println("四原色" + "666");
	
	System.out.println("四原色666");
  1. 使用final修饰的字符串常量的优化:

    对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的 “四原色” + str 和 “四原色” +“666” 效果是一样的。此时字符串常量池中存在的字符串常量有:“666”,"四原色666"故结果为true。

	String str1 = "四原色666"; 
	final String str = "666"; 
	String str2 = "四原色" + str;  
	System.out.println((str1 == str2));
1.2内存模型
1.2.1 String的堆栈存储模型
	String str = "四原色666";
	String str1 = "四原色666";
	String str2 = "四原色";
	String str3 = new String("666");
	System.out.println(str == str1);//true
	System.out.println(str1 == str3);//false

​ 1. 常量池中不存在两个相同的对象,所以str和str1都是指向JVM字符串常量池中的"四原色666"。new关键字一定会产生一个对象,并且这个对象存储在堆中。

​ 2. String str3 = new String(“333”)产生了两个对象:保存在栈中的str3和保存堆中的String对象。

​ 3. 当执行String str = "四原色666"时,JVM首先会去字符串常量池中检查是否存在"四原色666"对象,如果不存在,则在字符串常量池中创建"四原色666"对象,并将"四原色666"对象的地址返回给str1;如果存在,则不创建任何对象,直接将字符串常量池中"四原色666"对象的地址返回给str1。

在这里插入图片描述


2.StringBuffer

2.1实例化StringBuffer
	/*源码*/
		public StringBuffer() {
	        super(16);
	    }
	
	    public StringBuffer(int capacity) {
	        super(capacity);
	    }
	
	    public StringBuffer(String str) {
	        super(str.length() + 16);
	        append(str);
	    }

	//分析这几个构造器可以知道,
	//SringBuffer初始字符空间为16.
	//也可以通过构造方法设置这个初始空间。
	//如果再追加字符串是,字符空间超出了当前字符空间大小,
	//则调用this(seq.length() + 16),即字符空间大小每次增加时都增加16.
	
	//无参构造,默认为16个字符的空间
	StringBuffer sbf1 = StringBuffer();
	
	//指定字符长度构造StringBuffer对象
	StringBuffer sbf2 = StringBuffer(18);
	
	//指定字符串构造StringBuffer对象
	StringBuffer sbf3 = StringBuffer("四原色666");
2.2 常用方法
	public final class StringBuffer
	 extends AbstractStringBuilder 
	 implements java.io.Serializable, CharSequence{...}

​ StringBuffer类跟String类一样定义成final形式,主要是为了“效率”和“安全性”的考虑,若StringBuffer 被继承,由于它的高使用率,可能会降低它的性能。StringBuffer实现了Serializable接口和CharSequence接口,继承了AbstractStringBuilder类。

  1. 获取StringBuffer字符长度和字符的空间大小
/*源码*/
    @Override    
    public synchronized int length() {return count;}    
    @Override    
    public synchronized int capacity() {return value.length;}
    //length()获取的是StringBuffer对象值得长度;
    //capacity()获取的是StringBuffer对象字符的空间;
    //    如:
    StringBuffer sb = new StringBuffer();
    int len = sb.length();
    int cap = sb.capacity();
    //len = 0;
    //cap = 16;
  1. 设置字符空间大小
	/*源码*/
	@Override    
	public synchronized void setLength(int newLength) {
	        toStringCache = null;
	        super.setLength(newLength);    
	 }
	 StringBuffer sb = new StringBuffer();
	 //默认字符空间大小为16sb.setLength(10);
	 //设置字符空间大小为10
  1. 获取字符,设置字符
 	/*源码
 	 	@Override   
 	 	 public synchronized char charAt(int index) {        
 	 	 	if ((index < 0) || (index >= count))            
 	 	 		throw new StringIndexOutOfBoundsException(index);        
 	 	 	return value[index];    
 	 	 }    
 	 	 @Override    
 	 	 public synchronized void setCharAt(int index, char ch) {       
 	 	  	if ((index < 0) || (index >= count))            
 	 	  		throw new StringIndexOutOfBoundsException(index);        
 	 	  	toStringCache = null;       
 	 	    value[index] = ch;    
 	 	}*/
 	 	
 	 	StringBuffer sb = new StringBuffer("四原色yyds");
 	 	char fistChar = sb.charAt(0);
	 	//获取索引为0的字符sb.setCharAt(sb.length()-1,'!');
	 	//设置最后一个字符为!
  1. 向字符串中追加字符/字符串
       //源码
	@Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    public synchronized StringBuffer append(StringBuffer sb) {
        toStringCache = null;
        super.append(sb);
        return this;
    }
    @Override
    synchronized StringBuffer append(AbstractStringBuilder asb) {
        toStringCache = null;
        super.append(asb);
        return this;
    }
    @Override
    public synchronized StringBuffer append(CharSequence s) {
        toStringCache = null;
        super.append(s);
        return this;
    }
    @Override
    public synchronized StringBuffer append(CharSequence s, int start, int end){
        toStringCache = null;
        super.append(s, start, end);
        return this;
    }
    @Override
    public synchronized StringBuffer append(char[] str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    @Override
    public synchronized StringBuffer append(char[] str, int offset, int len) {
        toStringCache = null;
        super.append(str, offset, len);
        return this;
    }
    @Override
    public synchronized StringBuffer append(boolean b) {
        toStringCache = null;
        super.append(b);
        return this;
    }
    @Override
    public synchronized StringBuffer append(char c) {
        toStringCache = null;
        super.append(c);
        return this;
    }
    @Override
    public synchronized StringBuffer append(int i) {
        toStringCache = null;
        super.append(i);
        return this;
    }
    @Override
    public synchronized StringBuffer append(long lng) {
        toStringCache = null;
        super.append(lng);
        return this;
    }
    @Override
    public synchronized StringBuffer append(float f) {
        toStringCache = null;
        super.append(f);
        return this;
    }
    @Override
    public synchronized StringBuffer append(double d) {
        toStringCache = null;
        super.append(d);
        return this;
    }
  1. 删除字符/字符串
    /*源码
    @Override    
    public synchronized StringBuffer delete(int start, int end) {
            toStringCache = null;        
            super.delete(start, end);        
            return this;    
    }   
    @Override    
    public synchronized StringBuffer deleteCharAt(int index) {        
    	toStringCache = null;        
    	super.deleteCharAt(index);        
    	return this;    
   }*/
  1. 字符串的替换
 //*源码
 @Override    
 public synchronized StringBuffer replace(int start, int end, String str) {
         toStringCache = null;        
         super.replace(start, end, str);        
         return this;    
 }
  1. 获取子串
    //*源码
    @Override    
    public synchronized String substring(int start) {
            return substring(start, count);
    }    
    @Override    
    public synchronized CharSequence subSequence(int start, int end) {
            return super.substring(start, end);    
    }    
    @Override    
    public synchronized String substring(int start, int end) {
            return super.substring(start, end);    
    }
  1. 插入字符/字符串
	//*源码@Override
    public synchronized StringBuffer insert(int index, char[] str, int offset,
                                            int len)
    {
        toStringCache = null;
        super.insert(index, str, offset, len);
        return this;
    }
    @Override
    public synchronized StringBuffer insert(int offset, Object obj) {
        toStringCache = null;
        super.insert(offset, String.valueOf(obj));
        return this;
    }
    @Override
    public synchronized StringBuffer insert(int offset, String str) {
        toStringCache = null;
        super.insert(offset, str);
        return this;
    }
    @Override
    public synchronized StringBuffer insert(int offset, char[] str) {
        toStringCache = null;
        super.insert(offset, str);
        return this;
    }
    @Override
    public StringBuffer insert(int dstOffset, CharSequence s) {
        super.insert(dstOffset, s);
        return this;
    }
    @Override
    public synchronized StringBuffer insert(int dstOffset, CharSequence s,
            int start, int end)
    {
        toStringCache = null;
        super.insert(dstOffset, s, start, end);
        return this;
    }
    @Override
    public  StringBuffer insert(int offset, boolean b) {
       super.insert(offset, b);
        return this;
    }
    @Override
    public synchronized StringBuffer insert(int offset, char c) {
        toStringCache = null;
        super.insert(offset, c);
        return this;
    }
    @Override
    public StringBuffer insert(int offset, int i) {
        super.insert(offset, i);
        return this;
    }

    @Override
    public StringBuffer insert(int offset, long l) {
        super.insert(offset, l);
        return this;
    }
    @Override
    public StringBuffer insert(int offset, float f) {
        super.insert(offset, f);
        return this;
    }

    @Override
    public StringBuffer insert(int offset, double d) {
        super.insert(offset, d);
        return this;
    }
  1. 获取字符/字符串索引
     //*源码@Override
    public int indexOf(String str) {
        return super.indexOf(str);
    }
    @Override
    public synchronized int indexOf(String str, int fromIndex) {
        return super.indexOf(str, fromIndex);
    }
    @Override
    public int lastIndexOf(String str) {
        return lastIndexOf(str, count);
    }
    @Override
    public synchronized int lastIndexOf(String str, int fromIndex) {
        return super.lastIndexOf(str, fromIndex);
    }
  1. toString()方法
	//*源码
	@Override    
	public synchronized String toString() {
	        if (toStringCache == null) {
	                    toStringCache = Arrays.copyOfRange(value, 0, count);        
	        }        
	        return new String(toStringCache, true);
	}
2.3 StringBuffer特性

StringBuffer很多方法都是synchronized 修饰的,由于这个原因StringBuffer是线程安全的,在多线程场景下使用可以保障数据的使用安全,但与此同时其使用效率也会大大折扣,比如说当前有多个线程正在互斥访问同一个Stringbuffer实例对象时,最多只能有一个线程可以享有这个SringBuffer对象,其他线程就要进入阻塞状态等待资源的释放。


3 StringBuilder

​ StringBuilder的原理和StringBuffer一样,不同之处在于StringBuilder不需要考虑线程安全,同样,Stringbuilder定义成final形式,实现了Serializable接口和CharSequence接口,继承了AbstractStringBuilder类。

public final class StringBuilder
    extends AbstractStringBuilder    
    implements java.io.Serializable, CharSequence{...}
3.1 StringBuilder实例化
	/*源码
	public StringBuilder() {
        super(16);
    }
    public StringBuilder(int capacity) {
        super(capacity);
    }
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
    public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }*/
//分析这几个构造器可以知道:
//StringBuilder与SringBuffer一样,初始字符空间都为16.
//也可以通过构造方法设置这个初始空间。
//如果再添加字符串时,则调用this(seq.length() + 16),
//即字符空间大小每次增加时都增加16.
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder(10);
StringBuilder sb3 = new StringBuilder("四原色yyds");
StringBuilder sb4 = new StringBuilder();
3.2 StringBuilder常用方法
  1. 追加字符/字符串
/*源码*/
//添加一个对象,将对象转为String后追加到字符序列尾部
	@Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
//将一个字符串添加到字符序列尾部
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
//添加一个StringBuffer到字符序列尾部
    public StringBuilder append(StringBuffer sb) {
        super.append(sb);
        return this;
    }
//添加一个实例化CharSequence接口的字符串到字符串序列尾部
    @Override
    public StringBuilder append(CharSequence s) {
        super.append(s);
        return this;
    }
//添加一个实例化CharSequence接口的字符串到字符串序列start开始到end结尾之间
    @Override
    public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }
//添加一个字符数组到字符串序列尾部
    @Override
    public StringBuilder append(char[] str) {
        super.append(str);
        return this;
    }
//从offset开始长度为len的字符数组添加一个字符数组到字符串序列
    @Override
    public StringBuilder append(char[] str, int offset, int len) {
        super.append(str, offset, len);
        return this;
    }
//追加一个Boolean值到字符串序列尾部
    @Override
    public StringBuilder append(boolean b) {
        super.append(b);
        return this;
    }
//追加一个字符到字符串序列尾部
    @Override
    public StringBuilder append(char c) {
        super.append(c);
        return this;
    }
//追加一个整数到字符串序列尾部
    @Override
    public StringBuilder append(int i) {
        super.append(i);
        return this;
    }
//追加一个长整数到字符串序列尾部
    @Override
    public StringBuilder append(long lng) {
        super.append(lng);
        return this;
    }
//追加一个浮点数到字符串序列尾部
    @Override
    public StringBuilder append(float f) {
        super.append(f);
        return this;
    }
//追加一个double到字符串序列尾部
    @Override
    public StringBuilder append(double d) {
        super.append(d);
        return this;
    }
//追加一个Unicode字符到字符串序列尾部,其中参数为Unicode值
    @Override
    public StringBuilder appendCodePoint(int codePoint) {
        super.appendCodePoint(codePoint);
        return this;
    }
  1. 移除字符/字符串
 @Override
    public StringBuilder delete(int start, int end) {
        super.delete(start, end);
        return this;
    }
    @Override
    public StringBuilder deleteCharAt(int index) {
        super.deleteCharAt(index);
        return this;
    }
  1. 替换字符序列
    public StringBuilder replace(int start, int end, String str) {
            super.replace(start, end, str);        
            return this;
   }
  1. 插入字符/字符串序列
    @Override
    public StringBuilder insert(int index, char[] str, int offset,
                                int len)
    {
        super.insert(index, str, offset, len);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, Object obj) {
            super.insert(offset, obj);
            return this;
    }
    @Override
    public StringBuilder insert(int offset, String str) {
        super.insert(offset, str);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, char[] str) {
        super.insert(offset, str);
        return this;
    }
    @Override
    public StringBuilder insert(int dstOffset, CharSequence s) {
            super.insert(dstOffset, s);
            return this;
    }
    @Override
    public StringBuilder insert(int dstOffset, CharSequence s,
                                int start, int end)
    {
        super.insert(dstOffset, s, start, end);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, boolean b) {
        super.insert(offset, b);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, char c) {
        super.insert(offset, c);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, int i) {
        super.insert(offset, i);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, long l) {
        super.insert(offset, l);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, float f) {
        super.insert(offset, f);
        return this;
    }
    @Override
    public StringBuilder insert(int offset, double d) {
        super.insert(offset, d);
        return this;
    }
  1. 获取字符/字符序列索引
	public int indexOf(String str) {
        return super.indexOf(str);
    }
    public int indexOf(String str, int fromIndex) {
        return super.indexOf(str, fromIndex);
    }
    public int lastIndexOf(String str) {
        return super.lastIndexOf(str);
    }
    public int lastIndexOf(String str, int fromIndex) {
        return super.lastIndexOf(str, fromIndex);
    }
  1. 字符串序列翻转
	public StringBuilder reverse() {
	        super.reverse();        
	        return this;    
	}
  1. toString方法
  	public String toString() {return new String(value, 0, count);}
3.3 StringBuilder特性

与StringBuffer一样具有以下特性:

  1. 长度可变
  2. 可以存储不同类型的数据
  3. 最终转成字符串进行使用
  4. 可以对字符串进行修改

但是,在所有实现方法上与Stringbuffer不同的是没有关键字synchronized,所有StringBuilder是线程不安全的,在多线程场景下使用会造成数据不安全。另一方面,没有加锁释放锁过程,在执行速度上比StringBuffer要快很多。


4.三剑客之间的区别与联系

4.1联系

在这里插入图片描述

4.2区别
  1. String: 是不可变类,一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁,适合少量字符串操作场景,涉及到频繁字符串操作是不在适用。再次给String 赋值时,并不是对原来堆中实例对象进行重新赋值,而是生成一个新的实例对象,并且指向这个字符串,String 则指向最新生成的实例对象,之前的实例对象仍然存在,如果没有被再次引用,则会被垃圾回收。
  2. StringBuffer: 初始字符空间为16,线程安全,适合多线程场景下的应用,但是性能低。 StringBuffer表示可变字符序列,当一个StringBuffer被创建,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列,并不改变他的引用值,而且常量池中被改变的是原有的字符串常量。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
  3. StringBuilder: 初始字符空间为16,线程不安全,适合单线程场景下的应用,所以性能略高。 StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值