Java源码阅读计划(1) String<I>

Java源码阅读计划(1) String类

1.1不变性

HashMapkey建议使用不可变类,比容String这种,这里的不可变类指的色类中的一个值一旦初始化,将无法改变,如果修改,那就将会还是新的一个类。接下来我简单的演示一下:

        String s = "hello";
        s = "world";

非常简单的例子,我们看看第一行s的地址

再看看第二行s的地址

我们打开rt.jar,再打开java底下的lang包,找到String类,

在这里我们看到了两个final,
1.首先是类上的finalString无法被继承,也就是说所有String中的方法无法被继承覆写
2.接着是保存字符串的char数组,同样的被final修饰,也就是说value数组一旦被初始化,它的内存地址是无法被修改的,value的权限是private,外部访问不到,String也没开放修改值的方法,所以我们可以认为value一旦被赋值,内存地址是无法被修改的。
这就是String不变性的原因,当我们想设计一个不变性类的时候,可以模仿这种样式。

所以大多数String的方法,都必须有返回值的。

1.2相等判断

String类中,有两个判断相等的方法equals()equalsIgnoreCase(),接下来我详细的讲讲这两个方法。
equals()相信大家并不陌生,Java学习之初,就有一个equals()==的区别这一个知识点,这区别今后再立一个专题来谈谈。

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        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) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

equals()的方法设计的很巧妙,依照String的底层结构进行设计,先进行对象判断,接下先用长度,然后再一个一个字符进行比较,对方法性能有优化。
接着再看看equalsIgnoreCase(),这个方法是忽略大小写的相等比较

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

又是一个巧妙设计,利用&&的短路判断有性能的优化,接下来看看regionMatches()方法,

    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;
    }

逻辑很易懂,这里虽然统一使用了大写作为比较标准,可之后又使用小写再进行判断,这是Java为了针对Georgian(格鲁吉亚)字母表奇怪的大小写转换规则而专门又增加了一步判断,就是转换成小写再比较一次。

1.3替换

替换也是平常常用的一个功能,有replace()替换所有选定字符,有relaceAll() 替换字符串所有匹配给定的正则表达式的子字符串,还有replaceFirst()等,在特定位置替换的方法。
先讲讲replace()Java中的replace()有两种重载形式,一种是单字符,另外一种是字符串,

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 replace(CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }

另外一个方法,CharSequence是一个接口,与String不同,它是可读可写序列,至于下面的,QAQ等我看完Pattern类之后在进行详细分析。
接下来说说replaceAll(),该方法替换字符串所有匹配给定的正则表达式的子字符串,

   public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

TODO:这个详解等Pattern类看完一起处理。
至于repalceFirst()也同样等Pattern解决完一起来

    public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }

原文地址:https://www.cnblogs.com/figsprite/p/11743962.html