学习JDK源码:String
Posted 时光与我恰经过
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习JDK源码:String相关的知识,希望对你有一定的参考价值。
用了好久的Java了,从来没有看过jdk的源码,趁着今天有点时间,拿出了jdk的源码看了下,今天先看了关于String的,毕竟开发中String类型使用最广泛。在我们下载安装jdk的时候,部分源码也已经同时存放在我们电脑里了,具体路径为jdk目录下的src.zip压缩包,解压即可。
java.lang.String
1 public final class String 2 implements java.io.Serializable, Comparable<String>, CharSequence
这是String类的声明,很明显它是由final类型声明的,所以它不能被继承,而它又实现了Serializable接口,代表它是可以被序列化的。
接着我们来看看类内部是怎么定义的
/** The value is used for character storage. */ private final char value[];
使用final类型的字符数组存储字符串内容,String初始化后就不能被改变。
有一种写法,String s = “abc”; s = “bcd”;当然这并不是改变了字符串s的值,只是将s指向了一个新的字符串,所以千万不要以为字符串是可以变的。
/** Cache the hash code for the string */ private int hash; // Default to 0
指定缓存字符串的hash code的值,默认为0
/** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L;
相当于java类的身份证。主要用于版本控制。
serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
有两种生成方式:
一个是默认的1L,比如:private static final long serialVersionUID = 1L;
一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL;
/** * Class String is special cased within the Serialization Stream Protocol. * * A String instance is written into an ObjectOutputStream according to * <a href="{@docRoot}/../platform/serialization/spec/output.html"> * Object Serialization Specification, Section 6.2, "Stream Elements"</a> */ private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
serialPersistentFields 用于指定哪些字段需要被默认序列化,如:
private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("name", String.class), new ObjectStreamField("a", Integer.TYPE) };
看了String类的构造方法,惊叹不已,源码中有足足15种构造方法,其中最常用的不外乎以下几种
public String(byte bytes[]) { this(bytes, 0, bytes.length); } public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } } public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); }
再往后看就是String类自身提供的一系列方法了:
// 返回字符串的长度 public int length() { return value.length; } // 字符串是否为空 public boolean isEmpty() { return value.length == 0; } // 字符串目标位置的字符 public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; } // 返回指定索引处的字符 public int codePointAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return Character.codePointAtImpl(value, index, value.length); } // 返回指定索引之前的字符 public int codePointBefore(int index) { int i = index - 1; if ((i < 0) || (i >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return Character.codePointBeforeImpl(value, index, 0); } // 返回此 String 的指定文本范围中的 Unicode 代码点数 public int codePointCount(int beginIndex, int endIndex) { if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) { throw new IndexOutOfBoundsException(); } return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex); } //返回从0处开始的第i个Code Point的位置 public int offsetByCodePoints(int index, int codePointOffset) { if (index < 0 || index > value.length) { throw new IndexOutOfBoundsException(); } return Character.offsetByCodePointsImpl(value, 0, value.length, index, codePointOffset); } //判断两个字符串是否相等 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; } //不区分大小写的情况下比较两个字符串是否相等 public boolean equalsIgnoreCase(String anotherString) { return (this == anotherString) ? true : (anotherString != null) && (anotherString.value.length == value.length) && regionMatches(true, 0, anotherString, 0, value.length); } //计算当前字符串比目标字符串长度大多少 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 hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; } //返回某个指定的字符串值在字符串中首次出现的位置 public int indexOf(int ch) { return indexOf(ch, 0); } public int indexOf(int ch, int fromIndex) { final int max = value.length; if (fromIndex < 0) { fromIndex = 0; } else if (fromIndex >= max) { // Note: fromIndex might be near -1>>>1. return -1; } if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) final char[] value = this.value; for (int i = fromIndex; i < max; i++) { if (value[i] == ch) { return i; } } return -1; } else { return indexOfSupplementary(ch, fromIndex); } } //返回某个指定的字符串值在字符串中最后一次出现的位置 public int lastIndexOf(int ch) { return lastIndexOf(ch, value.length - 1); } public int lastIndexOf(int ch, int fromIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) final char[] value = this.value; int i = Math.min(fromIndex, value.length - 1); for (; i >= 0; i--) { if (value[i] == ch) { return i; } } return -1; } else { return lastIndexOfSupplementary(ch, fromIndex); } } //从指定位置截取字符串直至最后一位 public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = value.length - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); } //截取字符串从beginIndex至beginIndex public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
//字符串拼接 public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } //字符串替换 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 boolean contains(CharSequence s) { return indexOf(s.toString()) > -1; } //将目标字符串中匹配的字符全部替换成另一字符串 public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } //按约定分隔符将目标字符串分割成多个字符串并返回字符串数组 public String[] split(String regex, int limit) { /* fastpath if the regex is a (1)one-char String and this character is not one of the RegEx‘s meta characters ".$|()[{^?*+\\", or (2)two-char String and the first char is the backslash and the second is not the ascii digit or ascii letter. */ 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 { // last one //assert (list.size() == limit - 1); list.add(substring(off, value.length)); off = value.length; break; } } // If no match was found, return this if (off == 0) return new String[]{this}; // Add remaining segment if (!limited || list.size() < limit) list.add(substring(off, value.length)); // Construct result 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); }
以上是关于学习JDK源码:String的主要内容,如果未能解决你的问题,请参考以下文章
JDK源码学习--String篇 关于String采用final修饰的思考