Java String 源代码分析
2016-03-03 22:00
507 查看
String类的字段主要有下面几个:
final char value[], 字符数组主要用于存放字符
final int offset,字符数组的第一个元素下标
final int count,字符数组中元素的数量统计
int hash,字符串的hash值
构造函数
如果我们平时这样定义数组,那么会得到一个空的字符数组,并且是不可变的。
String str = new String();
下一种使用字符串来初始化对象:
String str = new String(“abc”);
这里代码中处理了如果初始化的字符串两边有垃圾字符,或者是空格等的情况,会删除掉这些字符。
使用字符数组构造字符串
String str = new String(new char[]{‘a’,’b’});
其他还有很多灵活的构造函数,但是大多使用了Arrays的方法。
常用方法
返回字符串长度
判断字符串是否为空
根据下标查找元素:
判断字符串相等
从这里可以看出,字符串相等的比较,是先检查字符串的长度是否相同,如果相同,则每一个字符元素进行比较,如果有其中一个不一样,则返回false。
字符串比较
这个方法就比较玄妙了,首先将参数字符串的相关字段全部都复制一份出来,然后判断两个字符数组第一个元素下标是否相同。
如果相同:从下标开始到较小长度字符串进行循环,每个字符进行比较,如果遇到字符不相等的情况,则做减法。
如果不同,也是从按照较小长度字符串的数据进行循环,每个字符进行比较做减法。
startsWith(String prefix)
这里调用了另外一个startsWith方法,传入了从第几个元素下标开始比较。默认都是0.
这里做的也是遍历传入字符串的每一个元素,判断是否相同。
hashcode()
计算hashcode的方法使用了这个公式。
h = 31*h+val[off++]
hashcode的要求是,同一个字符串不论这个方法调用多少次,这个值总是不变的。而且不能和其他字符串计算出来的值一样。这样会造成冲突。就是说纯粹是为了确保唯一性。
这里使用31的原因是,31在CPU上做乘法时,采用左移计算性能更高。来自网络资料。
intern()
这个方法应该算是String类里面唯一一个不是用Java实现的了。其源代码如下:
public native String intern();
说明是个本地方法,用C++来实现的。这个方法的作用是什么呢?
先要说下字符串定义的方式:
String str = “abc”;
这种方式也可以定义字符串,不过定义的字符串全部都在常量池中有储存,如果一个String类型的对象调用了intern方法的话,那么会检查这个字符串是否在常量池中有相等的String,如果有则返回常量池的对象,如果没有,则在常量池中定义一个。这样做的办法是性能会好很多,String不在堆上。
看一个例子:
这个输出是:
false
true
true
显然,a,b不是同一个,但是b调用了intern方法后,就是和a同一个对象了。
final char value[], 字符数组主要用于存放字符
final int offset,字符数组的第一个元素下标
final int count,字符数组中元素的数量统计
int hash,字符串的hash值
构造函数
如果我们平时这样定义数组,那么会得到一个空的字符数组,并且是不可变的。
String str = new String();
public String() { this.offset = 0; this.count = 0; this.value = new char[0]; }
下一种使用字符串来初始化对象:
String str = new String(“abc”);
这里代码中处理了如果初始化的字符串两边有垃圾字符,或者是空格等的情况,会删除掉这些字符。
public String(String original) { int size = original.count; char[] originalValue = original.value; char[] v; if (originalValue.length > size) { // The array representing the String is bigger than the new // String itself. Perhaps this constructor is being called // in order to trim the baggage, so make a copy of the array. int off = original.offset; v = Arrays.copyOfRange(originalValue, off, off+size); } else { // The array representing the String is the same // size as the String, so no point in making a copy. v = originalValue; } this.offset = 0; this.count = size; this.value = v; }
使用字符数组构造字符串
String str = new String(new char[]{‘a’,’b’});
public String(char value[]) { int size = value.length; this.offset = 0; this.count = size; this.value = Arrays.copyOf(value, size); }
其他还有很多灵活的构造函数,但是大多使用了Arrays的方法。
常用方法
返回字符串长度
public int length() { return count; }
判断字符串是否为空
public boolean isEmpty() { return count == 0; }
根据下标查找元素:
public char charAt(int index) { if ((index < 0) || (index >= count)) { throw new StringIndexOutOfBoundsException(index); } return value[index + offset]; }
判断字符串相等
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
从这里可以看出,字符串相等的比较,是先检查字符串的长度是否相同,如果相同,则每一个字符元素进行比较,如果有其中一个不一样,则返回false。
字符串比较
public int compareTo(String anotherString) { int len1 = count; int len2 = anotherString.count; int n = Math.min(len1, len2); char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; if (i == j) { int k = i; int lim = n + i; while (k < lim) { char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; } k++; } } else { while (n-- != 0) { char c1 = v1[i++]; char c2 = v2[j++]; if (c1 != c2) { return c1 - c2; } } } return len1 - len2; }
这个方法就比较玄妙了,首先将参数字符串的相关字段全部都复制一份出来,然后判断两个字符数组第一个元素下标是否相同。
如果相同:从下标开始到较小长度字符串进行循环,每个字符进行比较,如果遇到字符不相等的情况,则做减法。
如果不同,也是从按照较小长度字符串的数据进行循环,每个字符进行比较做减法。
startsWith(String prefix)
public boolean startsWith(String prefix) { return startsWith(prefix, 0); } public boolean startsWith(String prefix, int toffset) { char ta[] = value; int to = offset + toffset; char pa[] = prefix.value; int po = prefix.offset; int pc = prefix.count; // Note: toffset might be near -1>>>1. if ((toffset < 0) || (toffset > count - pc)) { return false; } while (--pc >= 0) { if (ta[to++] != pa[po++]) { return false; } } return true; }
这里调用了另外一个startsWith方法,传入了从第几个元素下标开始比较。默认都是0.
这里做的也是遍历传入字符串的每一个元素,判断是否相同。
hashcode()
public int hashCode() { int h = hash; if (h == 0 && count > 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; }
计算hashcode的方法使用了这个公式。
h = 31*h+val[off++]
hashcode的要求是,同一个字符串不论这个方法调用多少次,这个值总是不变的。而且不能和其他字符串计算出来的值一样。这样会造成冲突。就是说纯粹是为了确保唯一性。
这里使用31的原因是,31在CPU上做乘法时,采用左移计算性能更高。来自网络资料。
intern()
这个方法应该算是String类里面唯一一个不是用Java实现的了。其源代码如下:
public native String intern();
说明是个本地方法,用C++来实现的。这个方法的作用是什么呢?
先要说下字符串定义的方式:
String str = “abc”;
这种方式也可以定义字符串,不过定义的字符串全部都在常量池中有储存,如果一个String类型的对象调用了intern方法的话,那么会检查这个字符串是否在常量池中有相等的String,如果有则返回常量池的对象,如果没有,则在常量池中定义一个。这样做的办法是性能会好很多,String不在堆上。
看一个例子:
package com.lenovo; public class StringTest { public static void main(String[] args) { String a = "abc"; String b = new String("abc"); System.out.println(a==b); System.out.println(a==b.intern()); System.out.println(a.equals(b)); } }
这个输出是:
false
true
true
显然,a,b不是同一个,但是b调用了intern方法后,就是和a同一个对象了。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android之获取手机上的图片和视频缩略图thumbnails
- android string.xml文件中的整型和string型代替
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序