Java复习基础------字符串

字符串

字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。

1.创建字符串常见的两种方式

① 直接赋值创建:会在字符串常量池中

String str1 = "hello";

② 通过构造方法创建:在堆内存中创建

String str2 = new String("hello");
两种方式的比较
String str1 = new String("hello");
String str2 = "hello";
String str3 = "hello";
System.out.println(str1 == str2);    		//false
System.out.println(str2 == str3);    		//true
System.out.println(str1.intern() == str3);    //true

内存结构图:

在这里插入图片描述

注意点:直接赋值方式只会开辟一块内存空间,并且会存在常量池中,而构造方法创建的方式会开辟两块内存空间,其中一块会被垃圾回收,不能进入常量池中,可以通过intern()方法进行手工入池,

2.String的不可变性

String的源码分析:

String的不可变性不只是因为value[]不可变,它仅仅是value[]的引用地址不可变,内部的数据还是可以被改变的,final的修饰只是value数组不能被继承,以免被外部修改,但主要的是String类中的所有操作都没有改变过value数组。

//String被final修饰,说明String不可以被继承
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];   //底层维护了一个private的不可变的char型数组
}

String类重写了Object类的equals()方法,首先比较两个对象的地址值,如果相同则直接返回true,否则将会比较两个对象的值是否相等

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        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;
}
不可变性的好处:
  • 可以实现多个变量引用堆内存中的同一个字符串实例,避免内存的开销
  • HashMap中经常用String作为key,计算hash值只用计算一次,而且确保了key的唯一性
  • String天生线程安全,可以用在多线程场景

3.String,StringBuffer,StringBuilder

在这里插入图片描述

下面拿StringBuffer源码举例:

/**  char[] value;  继承了父类AbstractStringBuilder的可变char[] 默认大小为16 **/
public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    
    //调用父类AbstractStringBuilder的构造方法,
	public StringBuffer() {
        super(16); 
    }
    
    //append方法重写了AbstractStringBuilder的append方法
    @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
}
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();      //如果str==null则返回一个值null的AbstractStringBuilder对象
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

**扩容:**如果新的字符串长度大于value[]的长度则扩容

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}
private int newCapacity(int minCapacity) {
    // overflow-conscious code
    //扩容后长度为原来的两倍+2,如果扩容后的长度还小于新的字符串的长度,则将新字符串的长度赋值给扩容的长度
    int newCapacity = (value.length << 1) + 2;    
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}
//如果扩容的长度超过了数组允许的最大长度MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8),则进行如果新字符串长度大于int最大值则抛异常,否则判断新字符串的长度是否大于数组最大长度,大于则将维持新字符串长度,否则将容量扩为数组最大的长度
private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}
三者区别:

String的+运算符(拼接字符串的操作):

public static void main(String[] args) {
	String s1 = "a";
	String s2 = "b";
	String s3 = s1 + s2;
}

反编译class文件后:

public static void main(String args[])
{
    String s1 = "a";
    String s2 = "b";
    String s3 = (new StringBuilder(String.valueOf(s1))).append(s2).toString();
}

可以看到String在字符串拼接的时候底层用的是StringBuilder的append()方法后通过toString()返回新的字符串

总结:

  • 在不常操作和改变字符串的情况下用String比较合适,因为大量的字符串操作会new出大量的StringBuider对象,造成系统的开销
  • 因为StringBuffer和StringBuilder底层的实现几乎一样,只是StringBuffer用了synchronized修饰保证了线程安全,所以StringBuffer效率相对于StringBuilder较低
  • 多线程场景下大量操作字符串下使用StringBuffer,单线程使用StringBuilder

参考链接:

https://www.cnblogs.com/zhangyinhua/p/7689974.html#_lab2_4_0

https://www.oschina.net/question/129471_37540

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值