内容:创建String 的方式,String比较方式,String类,实例对象的小区别,一些工具包
首先,查看String源码:有几个比较重要的点
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
}
class被final修饰,这意味着String不能被继承,也不能使用Object instanceof String得到bool;
private final char value[];
value对应的是String实例出来的具体的值对应的char[],被final修饰,意味着该值不能被修改(但是可以重新给实例对象指向新的地址)
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;
}
String重写equlas()equals是在不为空的情况下比较char的长度,长度相同 再一一比较char
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);
}
String 类下的方法substring 我们可以看到返回的值 是new String的,所以使用substring的时候并不会影响原对象本身。其他的方法也是如此。
在Java中有字符串常量池举个栗子
下面是对字符串“hello”的几种声明方式,发现value都是一样的。但是用"=="来进行比较的时候,前面三个是true.
最后一个与前面任何一个在栈内地址都不相同。
- 字符串常量池是为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串常量池,该池是Java堆内存中一个特殊的存储区域。
String str2 = "hell"+"o";
String str3 = "hello";
上面这两种在JVM字符串常量池中为什么不是创建了三个"hell",“o”,"hello"呢,因为JVM对字符串这个特殊的数据进行了特殊的处理。上面两种声明在字符串常量池中申请的是同一个。
- new String(“hello”);在字符串常量池中与上面几种申请的其实是同一处地址,但是为什么与前面几种方式的任意一种使用==的时候返回false。虽然在常量池中是同一个值,但是对应对象的"栈"却是不同的,new关键字创建的对象是开辟内存新的地址。
StringBuffer
是我们常用的字符串处理的一个类。
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{}
该类也是被final修饰的,意味着不能被继承。
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
在他的append字符串拼接值的方法是被synchronized 意味着该类在多线程中是线程安全的。
StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{}
StringBuilder同样被final修饰,该类也是不能被继承的最终。
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
没有被锁锁着,所以多线程下“写”不安全。
String对象被传值
private static void changesValue(String str){
str = "hello zhangsan";
}
public static void main(String[] args) {
String lisi = "lisi";
changesValue(lisi);
System.out.println(lisi);
lisi = "hello wangwu";
System.out.println(lisi);
}
结果:
lisi
hello wangwu
观察上面的结果可以发现,String为不可变类型,在方法内对String修改的时候,相当于传入的是String的副本,并不是对象本身,所以修改之后也只是修改备份,并不会修改对象本身的值。
但是使用StringBuffer或者StringBuilder的时候是可以进行修改的,因为StringBuffer下对应的具体的值并没有被final修饰,在本文的开头就看到String类下的value是被fianl修饰的。
private transient char[] toStringCache;//StringBuffer
private final char value[];//String
Utils
我常使用的String工具类:
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
里面有判空,去空格等处理。