【JDK8源码】java.lang.String类阅读笔记

本文深入剖析 Java 中 String 类的设计理念与实现细节,包括构造方法、常用方法如 equals、compareTo 和 substring 的工作原理,并探讨 String 不可变性的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【JDK8源码】java.lang.String类阅读笔记

前言

个人见解,有理解错误的地方望指正。

概述

Java中用来创建和操作字符串的类,一个不可变的类。

类的定义

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
  • 刚刚上面说到String是一个不可变的类,这里可以看到String类是用final修饰的,是一个不可继承不可变的类
  • 实现了Serializable接口,表示这个类可以被序列化
  • 实现Comparable接口,默认的比较器,用来比较两个字符的大小,实现了这个接口意味着类支持排序(按照实现方法内的规则排序),可以使用Collections.sort()或者Arrays.sort()等方法。
  • 实现了CharSequence接口,表示是一个有序的字符集合,提供了对序列字符的一些操作。

属性

    //存储字符串的数组
    //也是使用final修饰的,所以String还是不可变的,不可变只是指数组的引用不可变
    //数组是一段连续的内存地址,里面的某个值还是可以变的
    private final char value[];
    //缓存字符串的hash代码
    private int hash; 
    //序列化编号
    private static final long serialVersionUID = -6849794470754667710L;
    //也是用来参与序列化的一个属性
    private static final ObjectStreamField[] serialPersistentFields =new ObjectStreamField[0];

常见构造方法

  • String()
   //无参构造函数,创建一个空的字符串对象
   public String() {
       this.value = "".value;
   }
  • String(String original)
    //入参一个String类型,将String的value和hash都赋值给新的String
   public String(String original) {
       this.value = original.value;
       this.hash = original.hash;
   }
  • String(char value[])
   //入参一个char类型的数组,使用Arrays.copy()将参数数组的长度和内容赋值给新的该String的value
   public String(char value[]) {
       this.value = Arrays.copyOf(value, value.length);
   }
  • String(char value[], int offset, int count)
   //入参一个char类型数组,将数组从下标offset开始复制count个,再赋值String的value
    public String(char value[], int offset, int count) {
      //如果起始下标小于0,抛出异常
       if (offset < 0) {
           throw new StringIndexOutOfBoundsException(offset);
       }
       if (count <= 0) {
       //如果复制长度小于0,抛出异常
           if (count < 0) {
               throw new StringIndexOutOfBoundsException(count);
           }
           //如果复制长度=0,且起始下标<=数组长度,创建一个空的数组
           if (offset <= value.length) {
               this.value = "".value;
               return;
           }
       }
       // 如果起始下标大于数组长度-数组长度,抛出异常
       if (offset > value.length - count) {
           throw new StringIndexOutOfBoundsException(offset + count);
       }
       //调用copyOfRange方法复制数组
       this.value = Arrays.copyOfRange(value, offset, offset+count);
   }
  • String(byte bytes[], int offset, int length, String charsetName)
//从bytes[]数组的offset位置截取长度为length的字符,以charsetName编码复制给String的value
  public String(byte bytes[], int offset, int length, String charsetName)
           throws UnsupportedEncodingException {
       if (charsetName == null)
           throw new NullPointerException("charsetName");
           //用来判断长度是否超过的
       checkBounds(bytes, offset, length);
       this.value = StringCoding.decode(charsetName, bytes, offset, length);
   }
  • String(StringBuffer buffer)
  //入参一个String Buffer对象,将buffer的长度和内容复制给Sting的vlaue数组
    public String(StringBuffer buffer) {
       synchronized(buffer) {
           this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
       }
   }
  • String(StringBuilder builder)
   //和上面一样
       public String(StringBuilder builder) {
       this.value = Arrays.copyOf(builder.getValue(), builder.length());
   }

常用方法

  1. length():
//返回当前字符串长度,构造比较简单,直接返回了value数组的长度
 public int length() {
       return value.length;
   }
  1. isEmpty():
//判断字符串是否为空,判断value的长度是否等于0,如果为0则返回false,否则返回true
 public boolean isEmpty() {
        return value.length == 0;
    }
  1. charAt(int index):
   //获取字符串中的index索引处的值
    public char charAt(int index) {
    //判断索引值是否超过数组长度,超过则抛出异常
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        //否则返回数组中索引对应的值
        return value[index];
    }
  1. equals:
  • equals(Object object):
//将字符串和指定的对象作比较,如果相等返回true,否则返回false
   public boolean equals(Object anObject) {
       //先直接用==判断,即两个对象指向的引用地址是否是同一个,如果是直接返回true
        if (this == anObject) {
            return true;
        }
        //判断是否是String类型的
        if (anObject instanceof String) {
        //转换为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])
                    //只要有一个不相等就返回false
                        return false;
                    i++;
                }
                //否则返回true
                return true;
            }
        }
        //如果不是String类型直接返回false
        return false;
    }
  • equalsLgnoreCase(String value):
    //忽略大小写,将String与另一个String字符串作比较
    public boolean equalsIgnoreCase(String anotherString) {
    //如果指向同一地址,直接返回true,否则就判断字符串不为空,且两个字符串长度相同且字符相同
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }
    /**
    ignoreCase:是否忽略大小写
    tooffset:当前字符串起始位置
    other:要比较的字符串
    ppffset:参数字符的起始位置
    len:要比较的字符数
    **/
 public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // 先判断起始位置是否正确
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        //循环判断字符是否相等
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            //如果==判断为真,直接跳出循环进入下一次循环
            if (c1 == c2) {
                continue;
            }
            //否则判断是否需要忽略大小写
            if (ignoreCase) {
                //将字符转换为大写,再做比较
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }
                //转换为小写作比较
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            //不满足返回false
            return false;
        }
        return true;
    }
  1. compareTo
  • compareTo(String str)
//按字典顺序比较两个字符串
//如果当前字符串等于参数字符串返回0
//如果当前字符串小于参数字符串,返回负数
//如果当前字符串大于参数字符串,返回正数
  public int compareTo(String anotherString) {
        //获取当前字符串的长度
        int len1 =