Java String 源码分析
来源:互联网 发布:小米4没有4g网络设置 编辑:程序博客网 时间:2024/05/01 18:49
定义
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
可以看出:
①、String 是 final 的(不允许被继承)
②、继承了
Serializable(可以序列化和反序列化)、
Comparable(可以进行自定义的字符串比较)、
CharSequence(一个可读序列。此接口对许多不同种类的 char 序列提供统一的只读访问。StringBuilder 和StringBuffer也实现了这个接口)接口。
属性
/** 用于存放字符串的数组 */ private final char value[];
由 final 可知,String 的内容一旦被初始化后,其不能被修改的(是指其内容不能被修改,其引用还是可以指向其他的内容)。
注意一点:String 是基于字符数组 char[] 实现的
/** 缓存字符串的 hash Code */ private int hash; // 默认为 0
/** 因为实现了序列化接口,所有拥有序列化ID */ private static final long serialVersionUID = -6849794470754667710L;
总结:如果你需要一个可修改的字符串,应该使用StringBuffer 或者 StringBuilder。
方法
构造方法
①、无参数构造函数(会创建一个空的字符序列,可是字符串是不可变的,所以不推荐使用)
public String() { this.value = "".value; }
②、使用字符串类型的对象来初始化(这个构造方法将会产生 2 个字符串对象,除非需要 original 的显式副本,否则不要使用此构造函数)
public String(String original) { this.value = original.value; this.hash = original.hash; }
③、使用字符数组来构造(将该字符数组复制到新的字符数组中)
public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }
public String(char value[], int offset, int 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; } } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); }
④、使用字节数组来构建 String(分为以下两种)
String(byte bytes[])String(byte bytes[], int offset, int length) // 从offset开始,长度为length 并以默认的 ISO-8859-1 编码转换成字符串
使用以下四种的话,就会使用 StringCoding.decode 方法进行解码,使用的解码的字符集就是我们指定的 charsetName 或者 charset 。
String(byte bytes[], Charset charset)String(byte bytes[], String charsetName)String(byte bytes[], int offset, int length, Charset charset)String(byte bytes[], int offset, int length, String charsetName)
⑤、使用 StringBuffer 和 StringBuider 来构造 String(很少用到,因为可以直接调用 toString() 方法)
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()); }
⑥、一个特殊的保护类型的构造方法(Java 7 提供的,直接引用指向 value[] 的地址,share 只能等于 true)
String(char[] value, boolean share) { // assert share : "unshared not supported"; this.value = value; }
Q:Java 7 为什么会提供这样一个方法?
A:1、性能好;2、节约空间;3、安全的
总结:如果你只需要创建一个字符串,推荐使用双引号 “”的方式,如果你需要在堆中创建一个新的对象,你可以选择构造函数的方式。
一般方法(提高效率的方法)
①、equals()方法:提高比较的效率
public boolean equals(Object anObject) { // 判断是否为同一对象 if (this == anObject) { return true; } // 判断 anObject 是不是 String 类型 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; // 循环比较每一个 char 值 while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
②、hashCode()方法:hash 地址越大,所谓的“冲突”就越少,查找起来效率也会提高。
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; // 数学公式:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]*31^0 for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
③、substring()方法:Java 7 提供了一种新的实现方式牺牲一些性能,避免内存泄露。 Java 6 时,是同一个数组中操作。Java 7 是创建一个新的数组。
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); } // 将原来的 char[] 中的值逐一复制到新的 String 中 return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
④、replaceFirst、replaceAll、replace区别:
replace 的参数是 char 和 CharSequence,即可以支持字符的替换,也支持字符串的替换;replaceAll 和 replaceFirst 的参数是 regex,即基于规则表达式的替换(如果所用的参数据不是基于规则表达式的,则与replace()替换字符串的效果一样。)
/** * value 为存储当前字符串对象的字符串数组名 * 优化了比较次数 * @param oldChar 将被替换掉的字符 * @param newChar 新字符 * @return *//* public String replace(char oldChar, char newChar) { //如果新字符和老字符相同,直接返回当前字符串对象 if (oldChar != newChar) { int len = value.length;//获取当前字符串长度 int i = -1; char[] val = value; //目的:为了防止 getfield(获取指定类的实例域,并将其值压入到栈顶)这个操作码的执行 //目的:找出将被替换的字符(oldChar)所在字符串数组中第一个字符的下标位置 while (++i < len) { // ①、当找到第一个将被替换的字符时,跳出循环;i 就记录了下标位置 // ②、如果没有找到,i==len 将不会进入下面的,直接返回当前字符串 if (val[i] == oldChar) { break; } } if (i < len) { //将第一个将被替换的字符(oldChar)之前的不需要被替换的字符赋值给新数组buf char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } // 从第一个将被替换的字符下标(i)开始,对字符进行替换操作 while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; }*/
其他方法
自行查看源码,简单易懂。
扩展
①、String对“+”的重载:就是使用 StringBuilder 以及他的 append()、toString() 两个方法。
比如:
String str = "str";String str1 = "this is" + str; // 等价于:String str1 = new StringBuilder("this is").append(str).toString();
②、在Java 7 中,switch 对字符串支持的实现。其实 switch 只支持一种数据类型,那就是整型,其他数据类型都是转换成整型之后再使用 switch 的。
③、String str = “abc”; 相当于 char data[] = {‘a’, ‘b’, ‘c’}; String str = new String(data);
- java String源码分析
- Java String 源码分析
- java String.indexof源码分析
- java中String源码分析
- Java String类源码分析
- Java源码分析之String
- Java源码分析之String
- Java 源码分析 ----- String类
- 【JAVA源码分析——Java.lang】String源码分析
- JDK源码分析:java.lang.String
- java.lang.String源码分析(1)
- java.lang.String源码分析(2)
- JDK源码分析:java.lang.String
- [Java]String类分析源码阅读
- Java 7 源码分析——String
- Java源码分析之String类
- Java源码剖析—2 String源码分析
- java.lang之java.lang.String 源码阅读及分析
- 从“熔断”和“降级”说起
- 人工智能里的数学修炼 | 矩阵的花样分解:特征值分解(EVD)、相似对角化、QR分解、Schur分解、奇异值分解(SVD)的概念纠缠与详解
- `gem_original_require': no such file to load redis requires Ruby version >= 2.2.2.
- OpenCV GaussianBlur() 图像平滑滤波
- Winform-信息管理系统源码分享(Access数据库)
- Java String 源码分析
- (2)简单体验---helloworld、namespace简单解读、Action简单解读
- 比较炫酷的ui框架
- url数据库
- 函数:引用file类对象及io类对象作为参数打印文本及显示文本
- 计算机中移位操作和乘除法的关系
- PHP实现几种基本排序算法--冒泡排序法,快速排序法,选择排序法,插入排序法
- 微信小程序开发之目录介绍
- INSTALL_FAILED_DUPLICATE_PERMISSION perm