Java源码之String
2016-04-26 15:47
573 查看
在String的源码上有这么一段注释:
Strings are constant; their values cannot be changed after they
are created. String buffers support mutable strings.
Because String objects are immutable they can be shared.
字符串是常量,在创建后,它们的值是不能改变的。字符串缓冲区支持可变字符串,因为字符串对象是不变的它们可以共享(即StringBuffer)。
String str = “abc”;等价于:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);
不仅在这几个方法,包括toUpperCase、toLowerCase、trim等方法都是自己本身或者调用的方法先对char数组进行操作,操作完成后生成一个新的String对象并返回。
小结:
1、String引用的的char数组value是一个private final定义的变量,我们没有权限改变这个数组的内容(反射机制是可以操作这个value引用的值的,但是除非脑子有病才会这么做吧),也不能改变这个char数组的引用(final的特性,参考final关键字)。
2、字符串的增删改等改变操作,都是自己本身或者调用的方法先对char数组进行操作,操作完成后生成一个新的String对象并返回。
Strings are constant; their values cannot be changed after they
are created. String buffers support mutable strings.
Because String objects are immutable they can be shared.
字符串是常量,在创建后,它们的值是不能改变的。字符串缓冲区支持可变字符串,因为字符串对象是不变的它们可以共享(即StringBuffer)。
String str = “abc”;等价于:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);
一、String的定义
//在Java中String类其实就是对字符数组的封装 public final class String implements java.io.Serializable, Comparable<String>, CharSequence { //定义的主要变量: /** The value is used for character storage. */ private final char value[];//常量,在构造器中初始化 /** Cache the hash code for the string */ private int hash; // Default to 0 //默认构造函数,使用此构造函数是不必要的,因为字符串是不可变的。 public String() { this.value = new char[0]; } //新建的字符串是original的副本,如非必要,这个构造函数是不必要的,因为字符串是不可变的。 public String(String original) { this.value = original.value; this.hash = original.hash; } //char数组的值拷贝到当前char数组中,char数组的变化不会影响新建的字符串。 public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } //这里还有几个byte数组转字符串的构造函数没有列出 //StringBuffer里面的字符串也是已char[] value的形式存储的,只不过StringBuffer是线程安全 //的,需要加 public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } } }
二、String的常用方法
1、获取字符串相关信息的操作
//字符串的长度,即char[]的长度 public int length() { return value.length; } public boolean isEmpty() { return value.length == 0; } //返回指定位置的char值 public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; } //通过特定的charset把当前字符串转变成char数组 public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, value, 0, value.length); } //与特定的对象比较,该对象不为空并且是一个字符串,具有相同的字符序列,则返回true。 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; } //字符串忽略大小写的的比较,首先看两个字符串的引用是否是同一个,如果不是的话就对字符串的char数组进行对比,相等就继续比较,不等先转成大写的char值比较,不然再转车些小的char值比较。 public boolean equalsIgnoreCase(String anotherString) { return (this == anotherString) ? true : (anotherString != null) && (anotherString.value.length == value.length) && regionMatches(true, 0, anotherString, 0, value.length); } //从字符串的char数组的toffset位置开始,与prefix比较,如果个数等于prefix.length()的char值与 //prefix的char值相等,则字符串是从 toffset以prefix为开头的字符串 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; // Note: toffset might be near -1& 4000 gt;>>1. if ((toffset < 0) || (toffset > value.length - pc)) { return false; } while (--pc >= 0) { if (ta[to++] != pa[po++]) { return false; } } return true; } public boolean startsWith(String prefix) { return startsWith(prefix, 0); } public boolean endsWith(String suffix) { return startsWith(suffix, value.length - suffix.value.length); } //s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 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; } //返回指定字符的在该字符串中的第一个位置的索引 // ch a character (Unicode code point) public int indexOf(int ch) { return indexOf(ch, 0);//正序遍历查找 } //返回指定字符的在该字符串中的最后一个位置的索引 public int lastIndexOf(int ch) { return lastIndexOf(ch, value.length - 1);//倒序遍历查找 } public int indexOf(String str) { return indexOf(str, 0); } public boolean contains(CharSequence s) { return indexOf(s.toString()) > -1; }
2、字符串的增删改操作
上面的是一些获取信息的基本操作,下面的操作源代码则反映了string的不可变性: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); } 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); } //将指定的字符串拼接在当前字符串之后,先把当前字符串的char数组copy到新的char数组buf中,在使用 //getChars方法把str的char数组添加到buf中,最后生成一个新的string并返回。 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; }
不仅在这几个方法,包括toUpperCase、toLowerCase、trim等方法都是自己本身或者调用的方法先对char数组进行操作,操作完成后生成一个新的String对象并返回。
小结:
1、String引用的的char数组value是一个private final定义的变量,我们没有权限改变这个数组的内容(反射机制是可以操作这个value引用的值的,但是除非脑子有病才会这么做吧),也不能改变这个char数组的引用(final的特性,参考final关键字)。
2、字符串的增删改等改变操作,都是自己本身或者调用的方法先对char数组进行操作,操作完成后生成一个新的String对象并返回。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 从源码安装Mysql/Percona 5.5
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序