String相关分析

1.String 是如何实现的?它有哪些重要的方法?

  • 在JDK1.8中,String内部实际存储结构为cahr数组

  • 有多个构造函数,无参构造函数,有参构造函数(char[]数组, StringBuilder,StringBuffer)

  • equals方法,主要用来比较两个字符串是否相等,可以传递Object参数,首先会通过instanceof方法判断是否为String类型。最后通过比较每个字符是否相等来判断。

  • compareTo方法比较两个字符串,返回结果为int类型的值,当两个字符不一样的时候返回char1-char2

2.为什么String类型要用final修饰

  • 高效:使用final能够缓存结果,在传参的时候不需要考虑谁会修改它的值。如果是可变类则可能需要重新拷贝出一个新值进行传参,性能上就差了。以JVM中字符串常量池进行举例,只有字符串不可变时才能实现字符串常量池
  • 安全:在调用系统级操作指令之前,可能会进行校验,如果是可变类,校验之后,它的值可能又改变了,可能会造成严重的系统崩溃

3. == 和 equals 的区别

== 对于基本数据类型来说,是用于比较 “值”是否相等的;而对于引用类型来说,是用于比较引用地址是否相同的。
查看源码我们可以知道Object中也有equals()方法,源码如下 其实就是==

public boolean equals(Object obj) {
    return (this == obj);
}

字符串则重写了equals方法

public boolean equals(Object anObject) {
//对象引用相同就直接返回了
    if (this == anObject) {
        return true;
    }
    // 判断需要对比的值是否为 String 类型,如果不是则直接返回 false
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
        //转换成char数组进行比较
            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;
}

4. String 和 StringBuilder、StringBuffer 的区别

  • 因为String是不可变的因此拼接字符串的话性能会比较差
  • 因此需要使用StringBuffer,它提供append和insert方法来用于字符串拼接,并且保证其线程安全
    由于StringBuffer保证了线程安全地,所以性能不高,在JDK1.5的时候引入了StringBuilder,其append方法与StringBuffer主要区别没有加synchronized。最后都是调用了AbstractStringBuilder的append方法
//这里的obj可以是String, 字符数组char[],还可以是抽象类AbstractStringBuilder的子类,CharSequence的实现类。主要还是前两个
@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;
}

//AbstractStringBuilder的append方法
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    //确保字符数组的大小够
    ensureCapacityInternal(count + len);
    //将str的字符全部加到value数组从count开始的下标处
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
    if (sb == null)
        return appendNull();
    int len = sb.length();
    ensureCapacityInternal(count + len);
    sb.getChars(0, len, value, count);
    count += len;
    return this;
}

5.String和JVM

  • String的常见创建方式有两种:new String() 的方式和直接赋值的方式,直接赋值的方式会先去字符串常量池中查找是否已经有此值,如果有则把引用地址直接指向此值,否则会先在常量池中创建,然后再把引用指向此值;而 new String() 的方式一定会先在堆上创建一个字符串对象,然后再去常量池中查询此字符串的值是否已经存在,如果不存在会先在常量池中创建此字符串,然后把引用的值指向此字符串,如下代码所示:
Strings1=new String("Java");
Strings2=s1.intern();
Strings3="Java";
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true

它们在JVM的位置如图所示
在这里插入图片描述

  • 注意点:JDK 1.7 之后把永生代换成的元空间,把字符串常量池从方法区移到了 Java 堆上。
    除此之外编译器还会对 String 字符串做一些优化,例如以下代码:
//代码 "Ja"+"va" 被直接编译成了 "Java" 
String s1 = "Ja" + "va";
String s2 = "Java";
System.out.println(s1 == s2);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值