String源码分析(基于JDK1.8)

记录一些自己浅显的见解,还有很多不足之处

目录

  • String源码分析
    • 定义
    • 常用构造方法
    • 常用方法
  • String常见面试题

String源码分析

定义

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    }
  • String类被final关键字修饰,不能被继承,创建后不可修改。
  • String类实现了Serializable接口,可以实现序列化。
  • String类实现了Comparable,可以比较大小。
  • String类实现了CharSequence接口,String本质是个char类型数组。

常用构造方法

//1.构造一个空的字符串序列
public String() {
    this.value = "".value;
}

//2.构造一个字符串,使之与源字符串相同,也就是创建一个传入字符串的副本
public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

//3.将字符数组转成字符串
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

//4.将字符数组的一部分转成字符串
public String(char value[], int offset, int count) {
    //offset是要转化的数组起始坐标,count是要转化的字符长度
    if (offset < 0) {
    throw new StringIndexOutOfBoundsException(offset);
    }
    if (count <= 0) {
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
         if (offset <= value.length) {
            this.value = "".value;
            return;
        }
    }
    //如果起始位置>字符数组长度 - 个数,则无法截取到count个字符,抛异常
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
        }
        //从offset开始,截取到offset+count位置,不包括offset+count位置
        this.value = Arrays.copyOfRange(value, offset, offset+count); 
}

常用方法

1.判空和判断字符串长度

//String的长度就是value数组的长度
public int length() {
    return value.length;
}

//判断String是否为空,为空返回true,否则返回false
public boolean isEmpty() {
    return value.length == 0;
}

2.Equals类型方法

//最常用的方法,比较两个字符串的值是否相同,重写了Object的equals方法,传参为Object类型
public boolean equals(Object anObject) {
    if (this == anObject) { //如果传入的对象跟当前对象是同一对象,则返回true,因为同一对象的地址相同,地址相同,值也相同
        return true;
    }
    if (anObject instanceof String) {   //判断anObject是否是String类型,过滤掉非String类型的
        String anotherString = (String)anObject;    //强转为String类型
        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;
}

//忽略大小写的比较,为String本身的方法,传参为String类型
public boolean equalsIgnoreCase(String anotherString) {
    return (this == anotherString) ? true
            : (anotherString != null)
            && (anotherString.value.length == value.length)
            && regionMatches(true, 0, anotherString, 0, value.length);
}
//不常用,公有的比较方法,传入的StringBuffer对象
public boolean contentEquals(StringBuffer sb) {
    return contentEquals((CharSequence)sb);
}

3.CompareTo类型方法

//常用函数,用来比较字符串大小,因为String实现了Comparable接口,所有重写了compareTo方法
//返回int类型,正数为大,负数为小,基于字符的ASSIC码比较
public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.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; //如果遍历结束,都相同,比较两个字符串长度
}

//忽略大小写的字符串比较,
public int compareToIgnoreCase(String str) {
    return CASE_INSENSITIVE_ORDER.compare(this, str);
}
//上面调用的比较器
public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                        = new CaseInsensitiveComparator();

4.常用功能方法

//返回自己,默认会自动调用
public String toString() {
    return this;
}

//String转Char数组并返回    
public char[] toCharArray() {
    // Cannot use Arrays.copyOf because of class initialization order issues
    //String 和Arrays 都属于rt.jar中的类,但是BootstrapClassloader 在加载这两个类的顺序是不同的。
    //所以当String.class被加载进内存的时候,Arrays此时没有被加载,所以直接使用肯定会抛异常。而System.arrayCopy是使用native代码,则不会有这个问题。
    char result[] = new char[value.length];
    System.arraycopy(value, 0, result, 0, value.length);
    return result;
}

//去除String首尾空格
public String trim() {
    int len = value.length;
    int st = 0;
    char[] val = value;    /* avoid getfield opcode */

    while ((st < len) && (val[st] <= ' ')) {
        st++;
    }
    while ((st < len) && (val[len - 1] <= ' ')) {
        len--;
    }
    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}

//String字符大小写转化
public String toLowerCase() {
    return toLowerCase(Locale.getDefault());
}
public String toUpperCase() {
    return toUpperCase(Locale.getDefault());
}

//是否含有CharSequence子类元素,常用于StringBuffer和StringBuilderS
public boolean contains(CharSequence s) {
    return indexOf(s.toString()) > -1;
}

//用于检测是否匹配给定的正则表达式,较高级,目前还没用过
public boolean matches(String regex) {
    return Pattern.matches(regex, this);   //实际使用的是Pattern.matches()方法
}

//String的拼接方法,用来拼接字符串
public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {    //如果长度为0,说明不需要拼接
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);   //拼接的本质是创建一个新的String对象
}

5.replace,replaceAll方法

//替换方法,将older字符全部替换为newChar
public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {
        int len = value.length;
        int i = -1;
        char[] val = value; /* avoid getfield opcode */

        while (++i < len) {
            if (val[i] == oldChar) {
                break;
            }
        }
        if (i < len) {
            char buf[] = new char[len];
            for (int j = 0; j < i; j++) {
                buf[j] = val[j];    //原理是创建新数组,全部复制过去
            }
            while (i < len) {
                char c = val[i];
                buf[i] = (c == oldChar) ? newChar : c;
                i++;
            }
            return new String(buf, true);
        }
    }
    return this;
}

//替换第一个旧字符
public String replaceFirst(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}

//用新的字符串替换旧的字符串
public String replace(CharSequence target, CharSequence replacement) {
    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
            this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}

//如果没有正则表达式限制,跟replace功能一样
public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

源码太多了,下次再更新吧

String常见面试题

1.笔试题

public class StringInterview {
    public static void main(String[] args) {
        //demo1,常量池的知识点
        //demo2,创建了几个对象,答案是两个
        //demo3,String构造器的特点,会复制一个常量池的副本生成一个新的对象放到堆空间里
        //demo4,Java中的常量优化机制
        //demo5.String中变量用"+",会生成StringBuffer或StringBuilder对象,用append连接,用toString转化成String字符串,地址存放在堆空间中
    }

    public static void demo5() {
        String s1="ab";
        String s2=s1+"c";
        String s3="abc";
        System.out.println(s2==s3);  //false,s3是存放在常量池里的,s2由于进行了字符串连接,使用了StringBuffer的toString和append方法,地址在堆中
        System.out.println(s2.equals(s3));  //true
    }

    public static void demo4() {
        String s1 = "a" + "b" + "c";
        String s2 = "abc";
        System.out.println(s1 == s2);   //true,Java中有常量优化机制,编译时会计算成最终结果
        System.out.println(s1.equals(s2));  //true
    }

    public static void demo1(){
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);   //true,常量池里有的,就不会再创建新的,没有的,就创建一个放到常量池中
        System.out.println(s1.equals(s2));  //true
    }
    public static void demo2(){
        //创建了几个对象?
        String str=new String("abc");  //创建了两个对象,一个是"abc"放在常量池中,一个new出来的副本放在堆空间中
    }
    public static void demo3(){
        String s1=new String("abc");
        String s2="abc";
        System.out.println(s1==s2); //false,new出来的对象是放在堆空间的,"abc"对象是放在常量池里的
        System.out.println(s1.equals(s2));  //true
    }
}

2.null和""的区别

/**
 * ""是字符串常量,也是一个String对象,对象就可以调用String里的方法
 * null是空常量,不能调用任何方法,否则会报空指针异常,null常量可以给任意引用类型赋值
**/
public class StringMethod {
    public static void main(String[] args) {
        String s6="";
        String s7=null;
        System.out.println(s6.isEmpty());  //true,isEmpty()是判断字符串是否为空
        System.out.println(s7.isEmpty());  //NullPointerException,空指针异常
    }
}

3.String,StringBuffer和StringBuilder的区别

  • String是不可变的字符序列
  • StringBuffer和StringBuilder是可变的字符序列
  • StringBuffer是线程安全的,效率低
  • StringBuilder和String是线程不安全的,效率高一些,
  • 效率从高到低:StringBuilder>String>StringBuffer

4.String和StringBuffer作为参数传递

  • String虽然是引用类型,但是作为参数传递的时候还是跟基本数据类型一样的,不改变其值
  • StringBuffer就是引用类型,作为参数传递会改变其值
public class StringBufferTest {
    public static void main(String[] args) {
        String s=new String("Hi");
        System.out.println(s);  //Hi
        change(s);
        System.out.println(s);  //Hi

        StringBuffer sb=new StringBuffer();
        sb.append("Hi");
        System.out.println(sb);  //Hi
        change(sb);
        System.out.println(sb);  //HiHelloWorld
    }

    private static void change(StringBuffer sb) {
        sb.append("HelloWorld");
    }

    private static void change(String s) {
        s+="HelloWorld";
    }
}

5.int与String的转换

->int转String

public class intToString {
    public static void main(String[] args){
        int s=100;
        System.out.println(s+""); //s+""空字符串可以int转String

        int s1=1000;
        System.out.println(String.valueOf(s1));//String.valueOf可以int转String

        int s2=10000;
        Integer i=new Integer(s2);
        System.out.println(i.toString());//int转Integer转String,不推荐使用

        int s3=10;
        System.out.println(Integer.toString(s3));//Integer.toString()
    }
}

->String转int

- String-Integer-int(Integer.intvalue())  //不推荐
- Integer.parseInt()

你可能感兴趣的:(源码分析)