java.lang.String 类可能是大家日常用的最多的类
String 类定义【源码】
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
}
String 是一个用 final 声明的常量类,不能被任何类所继承,而且一旦一个String对象被创建,包含在这个对象中的字符序列是不可改变的,包括该类后续的所有方法都是不能修改该对象的,直至该对象被销毁,这是我们需要特别注意的(该类的一些方法看似改变了字符串,其实内部都是创建一个新的字符串)接着实现了 Serializable接口,这是一个序列化标志接口,还实现了 Comparable 接口,用于比较两个字符串的大小(按顺序比较单个字符的ASCII码),最后实现了 CharSequence 接口,表示是一个有序字符的集合;
字段属性【源码】
/**用来存储字符串 */
private final char value[];
/** 缓存字符串的哈希码 */
private int hash; // Default to 0
/** 实现序列化的标识 */
private static final long serialVersionUID = -6849794470754667710L;
从源码中我们可以看出一个 String 字符串实际上是一个 char 数组。
构造方法【源码】
age:
String str1 = "abc";//注意这种字面量声明的区别,后面会详细介绍
String str2 = new String("abc");
String str3 = new String(new char[]{'a','b','c'});
String中常用方法:
a:equals(Object anObject) 方法 (较的是组成字符串的每一个字符是否相同-即内容)
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
String 类重写了 equals 方法,比较的是组成字符串的每一个字符是否相同,如果都相同则返回true,否则返回false。【这里需要注意与之对应的对比方法有 == 这里对比的是内存地址是否相等】还要注意一点的是:【在object中,equals()是用来比较内存地址的,但是String重写了equals()方法,所以这里有区别】
下面介绍一下String类中的一个本地方法:
intern() 方法
public native String intern();
当调用intern方法时,如果池中已经包含一个与该String内容相同【equals(Object)为true】
的字符串,则返回该字符串。否则,将此String对象添加到池中,并返回此对象的引用。这句话什么意思呢?就是说调用一个String对象的intern()
方法,如果常量池中有该对象了,直接返回该字符串的引用(存在堆中就返回堆中,存在池中就返回池中);如果没有,则将该对象添加到池中,并返回池中的引用。
String str1 = "hello";//字面量 只会在常量池中创建对象
String str2 = str1.intern();
System.out.println(str1==str2);//true
String str3 = new String("world");//new 关键字只会在堆中创建对象
String str4 = str3.intern();
System.out.println(str3 == str4);//false
String str5 = str1 + str2;//变量拼接的字符串,会在常量池中和堆中都创建对象
String str6 = str5.intern();//这里由于池中已经有对象了,直接返回的是对象本身,也就是堆中的对象
System.out.println(str5 == str6);//true
String str7 = "hello1" + "world1";//常量拼接的字符串,只会在常量池中创建对象
String str8 = str7.intern();
System.out.println(str7 == str8);//true
public static void main(String[] args) {
String A = "abc";
String B = "abc";
String C = new String("abc");
System.out.println(A==B); //true
System.out.println(A.equals(B)); //true
System.out.println(A==C); //false
System.out.println(A.equals(C)); //true
}
String A= “abc”,会先到常量池中检查是否有“abc”的存在,发现是没有的,于是在常量池中创建“abc”对象,并将常量池中的引用赋值给A;第二个字面量 String B= “abc”,在常量池中检测到该对象了,直接将引用赋值给B;第三个是通过new关键字创建的对象,常量池中有了该对象了,不用在常量池中创建,然后在堆中创建该对象后,将堆中对象的引用赋值给C,再将该对象指向常量池。String重写了equals()方法所以这里是用来比较内容的A.equals(C)返回true;注意:看上图红色的箭头,通过 new 关键字创建的字符串对象,如果常量池中存在了,会将堆中创建的对象指向常量池的引用。
String str1 = "hello";
String str2 = "helloworld";
String str3 = str1+"world";//编译器不能确定为常量(会在堆区创建一个String对象)
String str4 = "hello"+"world";//编译器确定为常量,直接到常量池中引用
System.out.println(str2==str3);//fasle
System.out.println(str2==str4);//true
System.out.println(str3==str4);//fasle
str3 由于含有变量str1,编译器不能确定是常量,会在堆区中创建一个String对象。而str4是两个常量相加,直接引用常量池中的对象即可。
OK,聊到这里我们就来说说开发中常考虑的字符串拼接吧~
String 被new时是要创建对象的,+ 号拼接同理也会创建对象,所以程序中尽量不要使用 + 拼接,应该尽量使用StringBuffer或者StringBuilder。