java语法基础篇二-String类

String类

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    @Stable
    private final byte[] value;
    private final byte coder;
    private int hash;
    
    ......
}

从类的定义可以看出:

  • String 类是 final 的,意味着它不能被子类继承
  • String 类实现了 Serializable 接口,意味着它可以序列化
  • String 类实现了 Comparable 接口,意味着最好不要用‘==’来比较两个字符串是否相等,而应该用 compareTo() 方法去比较
  • StringBuffer、StringBuilder 和 String 一样,都实现了 CharSequence 接口,所以它们仨属于近亲。由于 String 是不可变的,所以遇到字符串拼接的时候就可以考虑一下 StringBuffer 和 StringBuilder,它俩是可变的
  • Java 9 以前,String 是用 char 型数组实现的,之后改成了 byte 型数组实现,并增加了 coder 来表示编码。在 Latin1 字符为主的程序里,可以把 String 占用的内存减少一半。当然,天下没有免费的午餐,这个改进在节省内存的同时引入了编码检测的开销。
  • 每一个字符串都会有一个 hash 值,这个哈希值在很大概率是不会重复的,因此 String 很适合来作为 HashMap 的键值。

String具有不可变性

  • String 类被 final 关键字修饰,所以它不会有子类,这就意味着没有子类可以重写它的方法,改变它的行为。
  • String 类的数据存储在 byte[] 数组中,而这个数组也被 final 关键字修饰了,这就表示 String 对象是没法被修改的,只要初始化一次,值就确定了。

原因:

第一,可以保证 String 对象的安全性,避免被篡改,毕竟像密码这种隐私信息一般就是用字符串存储的。

第二,保证哈希值不会频繁变更。毕竟要经常作为哈希表的键值,经常变更的话,哈希表的性能就会很差劲。

第三,可以实现字符串常量池。

由于字符串的不可变性,String 类的一些方法实现最终都返回了新的字符串对象。例如replace、concat、substring方法

字符串常量池

由于字符串的使用频率实在是太高了,所以 Java 虚拟机为了提高性能和减少内存开销,在创建字符串对象的时候进行了一些优化,特意为字符串开辟了一个字符串常量池。

image.png

java8之后,移除了永久代,字符串常量池移到了堆中。

image.png

示例:

String s = new String("ikun");

使用 new 关键字创建一个字符串对象时,Java 虚拟机会先在字符串常量池中查找有没有‘ikun’这个字符串对象,如果有,就不会在字符串常量池中创建‘ikun’这个对象了,直接在堆中创建一个‘ikun’的字符串对象,然后将堆中这个‘ikun’的对象地址返回赋值给变量 s。”

“如果没有,先在字符串常量池中创建一个‘ikun’的字符串对象,然后再在堆中创建一个‘ikun’的字符串对象,然后将堆中这个‘ikun’的字符串对象地址返回赋值给变量 s。

String.intern()方法

详细参看美团技术团队深入解析 String.intern()

在 JAVA 语言中有8中基本类型和一种比较特殊的类型String。这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念。常量池就类似一个JAVA系统级别提供的缓存。

8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种:

  • 直接使用双引号声明出来的String对象会直接存储在常量池中。
  • 如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。但是在JDK7之后,字符串常量池迁到堆中,intern会将在常量池中存储对象的引用。

判断字符串相等

此问题也可以引申为.equals() 和 ‘==’ 操作符有什么区别

  • “==”操作符用于比较两个对象的地址是否相等。
  • .equals() 方法用于比较两个对象的内容是否相等

但是equals方法一定是比较对象内容相等的吗?
并不是,例如java所有的类都继承Object这个超类。默认的equals比较的是两个对象的地址。String类对equals方法进行了重写,所以是进行比较内容。

String类Java源码如下:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String aString = (String)anObject;
        if (coder() == aString.coder()) {
            return isLatin1() ? StringLatin1.equals(value, aString.value)
                    : StringUTF16.equals(value, aString.value);
        }
    }
    return false;
}
  • 首先进行地址比较,如果地址相等,则直接返回。
  • 判断是否是String类型对象
  • 如果是String类,再根据采用的编码进行内容比较
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值