Java 深入理解String字符串

String

在Java中String对象是对常见的数据类型了,那么面对String我们有什么问题呢?

  1. String常见的方法有那些
  2. equals()和compareTo()有什么不同
  3. 为什么String类型要用final修饰
  4. ==和equals的区别
  5. String、StringBuilder、StringBuffer的区别

String常见的方法有那些

length(): 获取字符串长度
trim():剔除空格
indexOf():查询字符串首次出现的下标位置
lastIndexOf():查询字符串首最后现的下标位置
contains():查询字符串中是否包含另外一个字符串
equals():比对象是否相同
compareTo():比较两个字符串是否相同
toLowerCase():将字符串转换成小写
toUpperCase():将字符串转换成大写
replace():替换字符串;replaceAll替换所有字符串
split():分割字符串

equals和compareTo有什么不同

String类重写了Object里的equals()方法
equals()方法中首先会判断类型是否为String类型;然后逐一判断每位字符是否相同,如果相同返回true,否则返回false
在String类中compareTo()方法参数类型只允许是String类型,而equals()方法不限制Object类型;本质上就是在内部判断中多了instanceof的判断

为什么String类型要用final修饰

准确得讲,String类被final修饰与其源码内value变量修饰为private和final得共同作用,才实现了String得不可变性;但即便这样对于String内部value 数组变量还是可以修改得,之所以没有修改是因为String内部没有对value数组的元素赋值;
见下:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

// private final 修饰得数组变量,内部值还是存在修改得风险(风险只限制于内部修改)
public final class Test {
    private final char value[];

    public Test(char[] value) {
        this.value = value;
    }

    public static void main(String[] args) {
        char val[] = {'a', 'b'};
        Test test = new Test(val);
        test.print();
        val[0] = 'b';
        test.print();
    }

    public void print(){
        Arrays.asList(value).stream().forEach(v ->{
            System.out.print(v);
        });
        System.out.println();
    }
}

//输出结果
ab
bb

回归正题:那么为什么这样来写呢?

”安全性“和”效率“

  1. 由于String类不能被继承,所以就不会被修改,这就避免了因为继承引起的安全隐患;
  2. String类在程序中出现的频率比较高,如果为了避免安全隐患,在它每次出现时都用final来修饰,这无疑会降低程序的执行效率,所以干脆直接将其设为final类已提高效率;

为设计常量池提供了基础

  • 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能
  • JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
    1.为字符串开辟一个字符串常量池,类似于缓存区
    2.创建字符串常量时,首先检查字符串常量池中是否存在该字符串
    3.存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中
  • 实现的基础
    1.实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突
    2.运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收

==和equals的区别

== 对于基本数据类型来说,是用于比较”值“是否相等得;而对于引用数据类型来说,是对引用地址比较的。
equals 比较的方法来源是Object对象中的equals方法;源码中equals方法实现是==来比较的,所以对于引用数据类型来讲,如果没有重写equals方法那么它们比较的是引用地址;分析String类的equals方法你可以发现,String类里重写了equals方法

// Object 里的equals方法
public boolean equals(Object obj) {
        return (this == obj);
    }
// String 里的equals方法
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;
    }

String、StringBuilder、StringBuffer的区别

  • StringBuilder
    StringBuilder继承了AbstractStringBuilder抽象类,在AbstractStringBuilder中提供了修改value数组的方法append,因此StringBuilder是一个可变的字符串;
//StringBuilder重写了抽象类方法
    @Override
    public StringBuilder append(String str) {
        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.getChars(0, len, value, count);
        count += len;
        return this;
    }
  • StringBuffer
    StringBuffer也继承了AbstractStringBuilder抽象类,同样也是一个可变字符串;它与StringBuilder的区别就是它是线程安全的;
//可以看到,append方法声明时
@Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值