IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 浅谈String的特点和具体的源码实现 -> 正文阅读

[Java知识库]浅谈String的特点和具体的源码实现

浅谈String的特点和具体的源码实现

1、String源码本质

String的基本使用是Java入门的一个必修课,在面试中有时候也往往会是第一道面试题,一些互联网大厂也喜欢从最基础的知识点入手,然后追问技术实现细节。所以本博客通过源码和对比方式对一些实现细节简单分析

以jdk8版本的源码来说,String是以final修饰的类,实际存储的数据结构为char类型的数组

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    // 用于存储字符串的值
    private final char value[];

    /** Cache the hash code for the string */
    // 缓存字符串的hashcode
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
    
    ...
}

2、构造方法

挑出String里的主要几个构造方法,String不仅可以传入String参数、char数组,而且可以传入StringBufferStringBuilder

// String 为参数的构造方法
public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}
// char[] 为参数构造方法
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}
// StringBuffer 为参数的构造方法
public String(StringBuffer buffer) {
    synchronized(buffer) {
        this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    }
}
// StringBuilder 为参数的构造方法
public String(StringBuilder builder) {
    this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

3、equals(Object)方法

equals(Object)方法比较两个字符串是否相等。String类重写了Object类的equals(Object)方法,比较的是字符串每个字符。

/**
 * Compares this string to the specified object.  The result is {@code
 * true} if and only if the argument is not {@code null} and is a {@code
 * String} object that represents the same sequence of characters as this
 * object.
 *
 * @param  anObject
 *         The object to compare this {@code String} against
 *
 * @return  {@code true} if the given object represents a {@code String}
 *          equivalent to this string, {@code false} otherwise
 *
 * @see  #compareTo(String)
 * @see  #equalsIgnoreCase(String)
 */
public boolean equals(Object anObject) {
    // 对象引用相同直接返回TRUE
    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 v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 循环对比字符串的每个字符
            while (n-- != 0) {
                // 其中有一个字符不相同返回FALSE
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

equals(Object)方法传入一个Object对象,会用instanceof判断是否为String类型,不是String类型直接返回FALSE

Object oStr = "123";
Object oInt = 123;
// 返回 true
System.out.println(oStr instanceof String); 
// 返回 false
System.out.println(oInt instanceof String); 

equals(Object)方法注释里,作者也提到了两个类似方法,@see #compareTo(String) @see #equalsIgnoreCase(String)equalsIgnoreCase(String)方法用于忽略字符串的大小写之后的字符串比较,compareTo(String)也是用于字符串比较的,具体和equals(Object)有什么不同?

4、compareTo(String)方法

compareTo(String):用于比较两个字符串,返回的结果为 int 类型的值

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    // 获取两个字符串长度值最小的length值
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    // 对比每一个字符
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            // 有字符不相等就返回差值
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

从源码也可以看出compareTo(String)方法也是遍历字符串的每一个字符,当两个字符串中有任意字符不相同时,返回c1 - c2。比如,两个字符串分别存储的是 1 和 2,返回值-1;如果两个字符串存储的是1和1,返回值0,;如果两个字符串存储的是2和1,返回值是1

equals(String)方法一样,compareTo(String)方法也有一个忽略大小写的比较方法compareToIgnoreCase(String)compareToIgnoreCase(String)用于用于忽略大小写后比较两个字符串。

5、compareTo(String) 和equals(Object) 对比

compareTo(String) 方法和 equals(Object) 方法,这两个方法都可以用于比较字符串

  • compareTo(String) 方法和 equals(Object) 方法的区别:
  • equals() 可以接收一个 Object 类型的参数,而 compareTo() 只能接收一个 String 类型的参数
  • equals() 返回值为 Boolean,而 compareTo() 的返回值则为 int。

6、其他方法

  • indexOf():查询字符串首次出现的下标位置
  • lastIndexOf():查询字符串最后出现的下标位置
  • contains():查询字符串中是否包含另一个字符串
  • toLowerCase():把字符串全部转换成小写
  • toUpperCase():把字符串全部转换成大写
  • length():查询字符串的长度
  • trim():去掉字符串首尾的空格
  • replace():替换字符串中的某些字符
  • split():把字符串按分隔符分割,返回字符串数组
  • join():把字符串数组转为字符串

拓展知识

上面对String的常用方法做了一个比较简单的介绍,下面给出面试中一个很常见的面试题,进行介绍,主要是学习理解,并非为了面试而面试

  • 为什么 String 类型要用 final 修饰?
    final 修饰的类都是一个不可继承类。那这样设计有什么好处呢?

Java 语言之父 James Gosling的回答是,他会更倾向于使用final,因为它能够缓存结果,当你在传参时不需要考虑谁会修改它的值;如果是可变类的话,则有可能需要重新拷贝出来一个新值进行传参,这样在性能上就会有一定的损失。
另一个原因是安全,当你在调用其他方法时,比如调用一些系统级操作指令之前,可能会有一系列校验,如果是可变类的话,可能在你校验过后,它的内部的值又被改变了,这样有可能会引起严重的系统崩溃问题,这是迫使 String 类设计成不可变类的一个重要原因。

总而言之就是用两个优点,一个是安全,另外一个是性能问题

  • == 和 equals 的区别是什么?
    1. ==:对比的是栈中的值,基本数据类型对比的是变量值,引用数据类型对比的是堆中内存对象的地址
    2. equals:Object中默认也是常用==进行比较,而String的equals进行重写,比较的是两个字符串的内容
  • String 和 StringBuilder、StringBuffer 有什么区别?
    1. String是不可变的,如果尝试修改String字符串,会重新生成一个对象;而StringBuffer、StringBuilder是可变的
    2. StringBuffer是线程安全的,StringBuilder是线程不安全的,所以StringBuilder的执行效率要快于StringBuffer
  • String 的 intern() 方法有什么含义?
public static void main(String[] args) {  
    String s1 = new String("abc");
	String s2 = "abc"; 
    // s1 == s2?
    String s3 = s1.intern();
    // s2 == s3?
}

答案:

  1. s1 == s2 false
  2. s2 == s2 true

Stringintern()方法,会检查字符串常量池中是否有“abc”字符串,如果有,返回改字符串引用,否,将“abc”添加到常量池中。

详情可以参考博客深入解析String#intern 美团技术团队

  • String和new String两张创建方式有什么区别?
    1. String str1 = “abc”; 最多创建一个String对象,最少是不创建对象。如果常量池中有“abc”,那么str1直接引用就可以,否则创建“abc”的内存空间,如何再引用。引号创建的字符串是直接量,在编译器就会存储到常量池中
    2. String str2 = new String(“abc”);最多创建两个对象,最少创建1个对象。new关键字,会在堆创建内存区域,在运行期才创建。
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-03 09:21:59  更:2022-05-03 09:22:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:49:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码