Java源码分析之String
来源:互联网 发布:网络灯谜群会2015 编辑:程序博客网 时间:2024/05/22 04:52
初学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();
- Java源码分析之String
- Java源码分析之String
- Java源码分析之String类
- java String源码分析
- Java String 源码分析
- java.lang之java.lang.String 源码阅读及分析
- Java源码之String
- Java源码之String
- JDK源码分析之String
- String源码分析之BeanFactory
- java String.indexof源码分析
- java中String源码分析
- Java String类源码分析
- Java 源码分析 ----- String类
- String源码分析之Java中的String为什么是不可变的以及replace方法源码分析
- java源码笔记之String
- java 源码之String类
- Java源码阅读之String
- LeetCode 136. Single Number
- Faster R-CNN(~ RPN + Fast R-CNN)
- 基于express中间件 搭建小型服务器(随笔)
- MySQL_内、左右连接及外键
- 一个简单实用的分离器件锂电池充电电路
- Java源码分析之String
- 数兔子问题
- 浅析SQL 中GO关键字的作用
- Dockerfile中ENTRYPOINT 和 CMD的区别以及RUN的作用
- Python利用SMTP发送邮件
- 《剑指offer》笔记-第5章(1)
- ssd目标检测整理
- noip2008T2火柴棒等式题解
- 搭建记录:springmvc + maven