Java源码分析之String

本文探讨了Java中的String类,澄清了它不是基本类型而是对char数组的封装。文章详细分析了String如何实现Serializable、Comparable和CharSequence接口,并解释了这些接口的作用。接着,文章逐一剖析了String的重要方法,包括equals、equalsIgnoreCase、compareTo、startsWith、indexOf、lastIndexOf、replace、split和trim,最后提到了intern方法,展现了String类的精妙之处。

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

初学Java经常会误认为String是java基本类型,实际上String并非Java的8个基本类型,String本质上是对char数组的封装
下面对String源码进行分析

public final class String implements java.io.Serializable, Comparable<String>,
        CharSequence {}

String类实现了Serializable,Comparable和CharSequence三个接口

Serializable是标记接口,用于标记实现此接口的类可以被序列化

Comparable:

package java.lang;

import java.util.*;

public interface Comparable<T> {

    public int compareTo(T o);
}

那么Comparable接口到底有什么用呢?简单的说,如果你想一个类的对象支持比较(排序),那就必须要实现Comparable接口。此接口内部只有一个要重写的方法int compareTo(T o),这个方法对两个字符串按字典排序的方式进行比较,返回两个字符串中第一个不同的字符的 ascii码差值

CharSequence:
是一个字符char序列,实现此接口的类有CharBuffer,String,StringBuffer(线程安全),StringBuilder(线程不安全),那么CharSequence接口到底有什么用呢?
就拿String中的方法contains来说,注意它的参数是CharSequence s,由于StringBuffer和StringBuilder都实现了CharSequence,那么就可以直接用StringBuffer和StringBuilder传参,可以减少一次转换

下面开始说说String类的私有变量和构造函数

    /*
    这个私有变量说明了String最重要的两个点:
    1.char value[]表明String实质是以字符数组的形式存放的
    2.final关键字表明String一旦创建就无法改变,对于String的
    重新赋值都是重新划分内存空间,创建了新的String
    */
    private final char value[];
    //缓存String的hashCode值 默认为0
    private int hash;

    //Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的
    private static final long serialVersionUID = -6849794470754667710L;

    private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
public class Demo {
    public static void main(String[] args) throws Exception {
        String str1 = "abcd";
        System.out.println(str1);// abcd

        String str2 = new String();
        System.out.println(str2);//

        String str3 = new String("abcd");
        System.out.println(str3);// abcd

        char[] c = { 'a', 'b', 'c', 'd', 'e', 'f' };
        String str4 = new String(c);
        System.out.println(str4);// abcdef
        String str5 = new String(c, 2, 3);
        System.out.println(str5);// cde

        int[] a = { 65, 66, 67, 68, 97, 98 };
        String str6 = new String(a, 2, 3);
        System.out.println(str6);// CDa

        byte[] b = { 65, 66, 67, 68 };
        String str7 = new String(b, 1, 3, "ASCII");
        System.out.println(str7);// BCD
        String str8 = new String(b, 1, 3);
        System.out.println(str8);// BCD
        String str9 = new String(b, "ASCII");
        System.out.println(str9);// ABCD
        String str10 = new String(b);
        System.out.println(str10);// ABCD

        StringBuffer sb1 = new StringBuffer("abcd");
        String str11 = new String(sb1);
        System.out.println(str11);// abcd

        StringBuilder sb2 = new StringBuilder("abcde");
        String str12 = new String(sb2);
        System.out.println(str12);// abcde

    }

}

接下来分析String的核心方法

import java.util.Date;

public class Demo2 {
    public static void main(String[] args) throws Exception {
        String str1 = "abcde";
        System.out.println(str1.length());// 5 返回String的长度
        System.out.println(str1.isEmpty());// false 判断String是否为空
        System.out.println(str1.charAt(1));// b 返回value[index]
        System.out.println(str1.codePointAt(1));// 98
        System.out.println(str1.codePointBefore(1));// 97
        /*
         Java中超出char编码范围(65536)的unicode字符由两个char组成
         codePointCount()是准确计算unicode(而不是char)字符的数量的方法
        */
        System.out.println(str1.codePointCount(1, 3));// 2 返回1-3之间的码点值
        System.out.println(str1.offsetByCodePoints(1, 3));// 4 返回从1偏移3个码点后的索引

        char[] c = new char[10];
        str1.getChars(0, 3, c, 0);// 把value[0-3)的值复制到c中(从0开始存放)
        for (char d : c) {
            System.out.print(d + " ");// a b c
        }
        System.out.println();

        byte[] b1 = str1.getBytes("ASCII");
        for (byte b : b1) {
            System.out.print(b + " ");// 97 98 99 100 101
        }
        System.out.println();
        byte[] b2 = str1.getBytes();
        for (byte b : b2) {
            System.out.print(b + " ");// 97 98 99 100 101
        }
        System.out.println();

        // str1.equals(abc):false
        System.out.println("str1.equals(" + "abc" + "):" + str1.equals("abc"));

        boolean f1 = str1.contentEquals(new StringBuffer("abcde"));
        System.out.println("str1.equals(" + "abcde" + "):" + f1);// str1.equals(abcde):true

        boolean f2 = str1.contentEquals(new StringBuilder("ABCDE"));
        System.out.println("str1.equals(" + "ABCDE" + "):" + f2);// str1.equals(ABCDE):false

        // str1.equalsIgnoreCase(ABCDE):true
        boolean f3 = str1.equalsIgnoreCase("ABCDE");
        System.out.println("str1.equalsIgnoreCase(" + "ABCDE" + "):" + f3);

        String str3 = "abcdE";
        System.out.println(str1.compareTo(str3));// 32 e-E
        System.out.println(str1.compareToIgnoreCase(str3));// 0
        System.out.println(str1.compareTo("abcdefg"));// -2 5-7
        System.out.println(str1.compareToIgnoreCase("abcdefg"));// -2

        // str1.regionMatches(0, str3, 0, str3.length()):false
        boolean f4 = str1.regionMatches(0, str3, 0, str3.length());
        System.out.println("str1.regionMatches(0, str3, 0, str3.length()):"+ f4);

        // str1.regionMatches(true,0, str3, 0,str3.length()):true
        boolean f5 = str1.regionMatches(true, 0, str3, 0, str3.length());
        System.out.println("str1.regionMatches(true,0, str3, 0, str3.length()):"+ f5);

        // str1.startsWith(bc,1):true
        boolean f6 = str1.startsWith("bc", 1);
        System.out.println("str1.startsWith(" + "bc" + ", 1):" + f6);

        // str1.startsWith(ab):true
        boolean f7 = str1.startsWith("ab");
        System.out.println("str1.startsWith(" + "ab" + "):" + f7);
        // str1.endwith(de):true
        boolean f8 = str1.endsWith("de");
        System.out.println("str1.endwith(" + "de" + "):" + f8);

        /*
         3105 31*(31*0+97)+98
         实际上ab的hashCode值就是把ab从31进制转化为10进制的值
        */
        System.out.println("ab".hashCode());

        System.out.println("abacd".indexOf(97));// 0
        System.out.println("abcd".indexOf(99, 2));// 2
        System.out.println("abababa".lastIndexOf(97));// 6
        System.out.println("aba".lastIndexOf(98, 0));// -1
        System.out.println("aababcabcd".indexOf("abcd"));// 6
        System.out.println("aababcabcdabcd".indexOf("abcd", 7));// 10
        System.out.println("ababab".lastIndexOf("ab"));// 4

        System.out.println("ababab".lastIndexOf("ab", 5));// 4
        System.out.println("ababab".lastIndexOf("ab", 4));// 4
        System.out.println("ababab".lastIndexOf("ab", 3));// 2

        System.out.println(str1.substring(2));// cde
        System.out.println(str1.substring(1, 3));// bc
        System.out.println(str1.subSequence(1, 3));// bc

        System.out.println("to".concat("get").concat("her"));// together
        System.out.println("ababab".replace('b', 'c'));// acacac

        System.out.println(str1.matches("([a-zA-Z])+"));// true

        System.out.println("aababcabcd".contains("ab"));// true
        System.out.println("aababcabcd".replaceFirst("[a][b]", "AC"));// aACabcabcd
        System.out.println("aababcabcd".replaceAll("[a][b]", "AC"));// aACACcACcd
        System.out.println("aababcabcd".replace("ab", "AC"));// aACACcACcd

        String[] s1 = "boo:and:foo".split(":", 2);
        for (String string : s1) {
            System.out.print(string + " ");// boo and:foo n>0 pattern模式执行n-1次
        }
        System.out.println();

        String[] s2 = "boo:and:foo".split(":", -2);
        for (String string : s2) {
            System.out.print(string + " ");// boo and foo n<0 pattern模式执行无限次
        }
        System.out.println();

        String[] s3 = "boo:and:foo".split("o", -2);
        for (String string : s3) {
            System.out.print(string + " ");// b :and:f
        }
        System.out.println();

        String[] s4 = "boo:and:foo".split("o", 0);
        for (String string : s4) {
            // b :and:f n=0 pattern模式执行无限次并省略末尾的空字符串
            System.out.print(string + " ");                             
        }
        System.out.println();

        String[] s5 = "boo:and:foo".split("o");
        for (String string : s5) {
            System.out.print(string + " ");// b :and:f
        }
        System.out.println();

        System.out.println("abcde".toUpperCase());// ABCDE
        System.out.println("Abcd".toLowerCase());// abcd

        System.out.println(" a bc de ".trim());// a bc de

        char[] c2 = str1.toCharArray();
        for (char d : c2) {
            System.out.print(d + " ");// a b c d e
        }
        System.out.println();

        System.out.println(String.format("%tF", new Date()));// 2017-09-02

        String str6 = null;
        // System.out.println(str6.toString()); //NullPointerException
        System.out.println(String.valueOf(str6));// null

    }

}
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class Demo3 {
    @Test
    public void fun1() {
        System.out.println(String.join("-", "java", "is", "cool"));// java-is-cool

        List<String> list = new ArrayList<String>();
        list.add("java");
        list.add("is");
        list.add("cool");
        System.out.println(String.join(" ", list));// java is cool
    }
}

源码分析:

1. equals方法

public boolean equals(Object anObject) {
        // 1.判断是否==,是就直接返回true(==的要求比equals更加严格)
        if (this == anObject) {
            return true;
        }
        // 2.判断anObject是否为String,是 接着判断 否则返回false
        if (anObject instanceof String) {

            String anotherString = (String) anObject;
            int n = value.length;
            // 3.判断二者长度是否一样,是就接着判断,否则返回false
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                // 4.依次比较所有元素,全部一样返回true,否则返回false
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

2. equalsIgnoreCase方法

public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }


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;
                }
            }
            return false;
        }
        return true;
    }

3. compareTo方法

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

        int k = 0;
        /*
         2.在0-lim范围内依次比较所有元素
           返回第一个不相同的char的差值(如果有的话)
        */
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        //3.否则返回字符串长度的差值
        return len1 - len2;
    }

4 . startsWith方法

public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;
        int to = toffset;
        char pa[] = prefix.value;
        int po = 0;
        int pc = prefix.value.length;

        //1.检查边界
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        //2.从to开始依次比较pc次 出现一次不一样返回false 否则返回true
        while (--pc >= 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

5. indexOf和lastIndexOf方法

beautiful code !

public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length, str.value, 0, str.value.length,
                fromIndex);
    }


static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount, int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }

        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {

            if (source[i] != first) {
                while (++i <= max && source[i] != first)
                    ;
            }

            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end
                        && source[j] == target[k]; j++, k++)
                    ;

                if (j == end) {

                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }

public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, 0, value.length, str.value, 0,
                str.value.length, fromIndex);
    }



static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount, int fromIndex) {

        int rightIndex = sourceCount - targetCount;
        if (fromIndex < 0) {
            return -1;
        }
        if (fromIndex > rightIndex) {
            fromIndex = rightIndex;
        }

        if (targetCount == 0) {
            return fromIndex;
        }

        int strLastIndex = targetOffset + targetCount - 1;
        char strLastChar = target[strLastIndex];
        int min = sourceOffset + targetCount - 1;
        int i = min + fromIndex;

        startSearchForLastChar: while (true) {
            while (i >= min && source[i] != strLastChar) {
                i--;
            }
            if (i < min) {
                return -1;
            }
            int j = i - 1;
            int start = j - (targetCount - 1);
            int k = strLastIndex - 1;

            while (j > start) {
                if (source[j--] != target[k--]) {
                    i--;
                    continue startSearchForLastChar;
                }
            }
            return start - sourceOffset + 1;
        }
    }

6. replace方法

public String replace(char oldChar, char newChar) {
        //1.判断oldChar和newChar是否一样 是就返回this 否则继续
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; 

            //2.找到第一个是oldChar的索引i
            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                //3.复制i之前的元素到buf中
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                //4.对i以及i之后的元素进行替换
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

7. split方法

public String[] split(String regex, int limit) {

        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&
            (ch < Character.MIN_HIGH_SURROGATE ||
             ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {  
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }

            if (off == 0)
                return new String[]{this};


            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));


            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

8. trim方法

public String trim() {
        int len = value.length;
        int st = 0;
        //可以提高性能
        char[] val = value;

        //1.从左向右遍历空白,得到第一个不是空白的索引st
        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        //2.从右向左遍历空白,得到最后一个空白的索引len
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        //3.通过substring(st,len)返回结果
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

9. intern方法

    /*
    A native method is a Java method whose implementation is provided by non-java code
    在Java中,用双引号声明出来的String对象会直接存储在常量池中。如果不是用双引号声明的String对象,可
    以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会
    把当前字符串放入常量池中,再返回。
    */
    public native String intern();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值