Java字符串
在平时开发的过程中,字符串操作应该是最常见的行为。而在Java中,String类大概是我们使用的最频繁的一个类了。今天我们就来初步研究下String的实现。说起看源码,就本能的感到一种对高阶程序员的一种畏惧,但当你打开源码的时候你会发现,String类3000多行代码有很多都是注释,真正的代码没有想像的多,这个也侧面说明了注释在开发当中的重要性。
String类声明和属性
1 | public final class String |
我们可以看到String类首先是final修饰的,所以不允许被继承和修改。其次String类实现了Serializable、Comparable、CharSequence三个接口;Serializable接口使String可序列化,Comparable接口使String类能互相比较,CharSequence接口提供了length()、charAt(int index)、subSequence(int start,int end)方法。
接下来是String类的四个属性,一个不可变的char数组用来存放字符串,一个int型的hash存放哈希值,serialVersionUID提供序列化ID,serialPersistentFields声明了一个可序列化的字段。从这里我们可以看出,String是对char数组的封装。
String构造方法
1 | //无参构造方法 |
每个构造方法都写了注释,在此就不赘述了。
String类常用方法
boolean equals(Object anObject)
1 | public boolean equals(Object anObject) { |
equals方法经常用到,它用来判断两个String对象中的value是否相等,判断流程如下:
- 判断引用是否相同。如果是,则为同一个String对象,肯定相等,若不同继续判断。
- 判断比较对象是否是String对象,若不是,返回false, 若是,则继续判断。
- 判断两个String对象维护的char数组长度是否相等,不想等则返回false,相等则继续判断。
- 从后往前单个字符比较,若都相等,则两个String相等,否则不想等。
int compareTo(String anotherString)
1 | public int compareTo(String anotherString) { |
这个方法利用字符相减和长度相减巧妙的判断了三种情况。
int hashCode()
1 | public int hashCode() { |
String类重写了hashCode方法,采用了多项式计算得到hash值,但是两个hash相同的String也有可能不想等,这里采用这种方式只是为了尽可能减少碰撞,提高HashMap等的效率。
startsWith()/endsWith()
1 | public boolean startsWith(String prefix, int toffset) { |
这几个方法通常用于判断一个字符串的开头或者结尾是否是特定格式的,比如找到一个doc文件或者判断url的协议是不是http。
String concat(String str)
1 | public String concat(String str) { |
将一个字符串添加到当前字符串后,通过判断str时候为空串来决定时候新建对象。
String replace(char oldChar,char newChar)
1 | public String replace(char oldChar, char newChar) { |
这个replace是替换字符,replace(String oldStr,String newStr)方法采用的正则表达式。
String trim()
1 | public String trim() { |
去掉字符串前后的空格。
String intern()
1 | /** |
intern()是一个native方法,上面给出了Jdk注释,大概意思就是如果常量池里面有当前字符串,返回该字符串的引用;没有的话就把当前字符串放进常量池,再返回该字符串的引用。关于intern()这个方法个人感觉用起来要慎重,因为一旦常量池里面的字符串达到一定规模之后性能会下降不少。由于没有接触过大规模数据的操作,等有机会接触了再详细说一说intern()。
总结
从上文我们可以看出,String对象是不可变的。String类中每一个看起来会修改String值发方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容,而最初的String对象则纹丝不动。