浅谈Java字符串
作者:网络转载 发布时间:[ 2015/10/21 10:37:25 ] 推荐标签:测试开发技术 .NET
public class StringHashCode {
public static void main(String[] args) {
\输出结果相同
String[] hellos = "Hello Hello".split(" " );
System.out.println(""+hellos[0].hashCode());
System.out.println(""+hellos[1].hashCode());
\输出结果相同
String a = new String("hello");
String b = new String("hello");
System.out.println(""+a.hashCode());
System.out.println(""+b.hashCode());
}
}
结论
String 类是final类,不可以继承。对String类型好的重用方式是组合 而不是继承。
String 有length()方法,数组有length属性
String s = new String(“xyz”); 创建了几个字符串对象?
两个对象,一个静态存储区“xyz”, 一个用new创建在堆上的对象。
String 和 StringBuffer,String Builder区别?
在大部分情况下 StringBuffer > String
Java.lang.StringBuffer 是线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。在程序中可将字符串缓冲区安全地用于多线程。而且在必要时可以对这些方法进行同步,因此任意特定实例上的所有操作好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是 “start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含 “startle”( 累加); 而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含 “starlet”。
在大部分情况下 StringBuilder > StringBuffer
java.lang.StringBuilder 一个可变的字符序列是 JAVA 5.0 新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步,所以使用场景是单线程。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的使用方法基本相同。
源码
String,StringBuffer,StringBuilder都实现了CharSequence接口。
public class StringHashCode {
public static void main(String[] args) {
\输出结果相同
String[] hellos = "Hello Hello".split(" " );
System.out.println(""+hellos[0].hashCode());
System.out.println(""+hellos[1].hashCode());
\输出结果相同
String a = new String("hello");
String b = new String("hello");
System.out.println(""+a.hashCode());
System.out.println(""+b.hashCode());
}
}
String的源码
public final class String{
private final char value[]; // used for character storage
private int the hash; // cache the hash code for the string
}
成员变量只有两个:
final的char类型数组
int类型的hashcode
构造函数
public String()
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){
// 判断offset,count,offset+count是否越界之后
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
这里用到了一些工具函数
copyOf(source[],length); 从源数组的0位置拷贝length个;
这个函数是用System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength))实现的。
copyOfRange(T[] original, int from, int to)。
构造函数还可以用StringBuffer/StringBuilder类型初始化String,
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());
}
除了构造方法,String类的方法有很多,
length,isEmpty,可以通过操作value.length来实现。
charAt(int index):
通过操作value数组得到。注意先判断index的边界条件
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
getChars方法
public void getChars(int srcBegin, int srcEnd,
char dst[], int dstBegin)
{
\边界检测
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
equals方法,根据语义相等(内容相等,而非指向同一块内存),重新定义了equals
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;
}
如果比较的双方指向同一块内存,自然相等;(比较==即可)
如果内容相等,也相等,比较方法如下:
首先anObject得是String类型(用关键字instanceof)
然后再比较长度是否相等;
如果长度相等,则挨个元素进行比较,如果每个都相等,则返回true.
还有现成安全的与StringBuffer内容比较
contentEquals(StringBuffer sb),实现是在sb上使用同步。
compareTo():
如果A大于B,则返回大于0的数;
A小于B,则返回小于0的数;
A=B,则返回0
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
regionMatches:如果两个字符串的区域都是平等的,
public boolean regionMatches(int toffset, String other, int ooffset,
int len)
{
//判断边界条件
while (len-- > 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
}
public boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len)
{
while (len-- > 0) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2) {
continue;
}
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
}
return false;
}
return true;
}
startsWith(String prefix, int toffset)
startsWith(String prefix)
endsWith(String suffix)
{
return startsWith(suffix, value.length
- suffix.value.length);
}
substring(int beginIndex,int endIndex)
除了条件判断:
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
字符串连接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);
对于StringBuffer和StringBuilder
StringBuffer 和 StringBuilder 都是继承于 AbstractStringBuilder, 底层的逻辑(比如append)都包含在这个类中。
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);//查看使用空间满足,不满足扩展空间
str.getChars(0, len, value, count);//getChars是利用native的array copy,性能高效
count += len;
return this;
}
StringBuffer 底层也是 char[], 数组初始化的时候定下了大小, 如果不断的 append 肯定有超过数组大小的时候,我们是不是定义一个超大容量的数组,太浪费空间了。像 ArrayList 的实现,采用动态扩展,每次 append 首先检查容量,容量不够先扩展,然后复制原数组的内容到扩展以后的数组中。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Java性能测试有哪些不为众人所知的原则?Java设计模式??装饰者模式谈谈Java中遍历Map的几种方法Java Web入门必知你需要理解的Java反射机制知识总结编写更好的Java单元测试的7个技巧编程常用的几种时间戳转换(java .net 数据库)适合Java开发者学习的Python入门教程Java webdriver如何获取浏览器新窗口中的元素?Java重写与重载(区别与用途)Java变量的分类与初始化JavaScript有这几种测试分类Java有哪四个核心技术?给 Java开发者的10个大数据工具和框架Java中几个常用设计模式汇总java生态圈常用技术框架、开源中间件,系统架构及经典案例等
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南