Java常用类之String、StringBuilder、StringBuffer
String类
String的特性
1.String类:代表字符串。Java程序中的所有字符串字面值(如:“abc”)都作为此类的实例实现
2.String是一个final类(不可被继承),代表不可变的字符序列
3.字符串是常量,用双引号引起来表示,它们的值在创建之后不能更改
4.String对象的字符内容是存在一个字符数组char value[]中的;
public final class String implements java.io.Serializable,Comparable, CharSequence{
private final char value[];
private int hash;
String:字符串,使用一对""引起来
* 1.String类是声明为final的,不可被继承
* 2.String实现了Serializable接口,表示字符串是支持序列化的
* 实现了Comparable接口,表示String可以比较大小
* 3.String内部定义了final char[] value用于存储字符串数据
* 4.String类代表不可变的字符序列。简称:不可变性
* 体现:1.当对字符创重新赋值时,需要重新指定内存区域赋值,不能使用原有的value修改
* 2.当对字符串重新拼接时,需要重新指定内存区域生成拼接后的值,不能拼接原有的值
* 3.当调用String的replace()方法时(修改字符或字符串),需要重新指定内存区域生成replace后的字符串
* 5.通过字面量的形式(区别于new)给字符串赋值,此时的字符串值声明在字符串常量池中
* 6.字符串常量池中是不会维护相同的字符串的
String s1 = “abc”;
String s2 = “abc”;
该图基于jdk1.6及以前 jdk1.7及以后已将字符串常量池移入堆中
String对象的创建
String str = "hello";
//本质上this.value = new char[0];(源码) 1.8 this.value = "".value;
String s1 = new String();
//this.value = original.value;
String s2 = new String(String original);
//this.value = Arrays.copyOf(value,value.length);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex,int count);
问题:
String str1 = “abc” 与 String str2 = new String(“abc”)的区别?
1.字符串常量存储在字符串常量池中,目的是共享
2.字符串非常量存储在堆中
两者的区别在于,String str1 = “abc” 直接将字符串常量池中的abc地址值赋值给了str1变量。而String str2 = new String(“abc”)是在堆中先创建了一个String对象,将这个String 对象中的 value属性指向了字符串常量池中的abc地址值,然后将堆中的String对象的地址值赋值给st2变量
该图基于jdk1.6及以前 jdk1.7及以后已将字符串常量池移入堆中
String对象的拼接
小测试
@Test
public void test2(){
String s1 = "my";
String s2 = "JavaBase";
String s3 = "myJavaBase";
String s4 = "my"+"JavaBase";
String s5 = s1 + "JavaBase";
String s6 = "my" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true 都指向字符串常量池中的myJavaBase对象
System.out.println(s3 == s5);//false s5指向的是堆中的String对象
System.out.println(s3 == s6);//false s6指向的是堆中的String对象
System.out.println(s3 == s7);//false s7指向的是堆中的String对象
System.out.println(s5 == s6);//false s5 和 s6 指向的是不同的堆中的String对象
String s8 = s5.intern();//获取常量池中的值
System.out.println(s3 == s8);//true
}
问题:String a = new String(“abc”); 这种方式,在内存中创建了几个对象
答:两个,1.new String()放在堆中的对象 2.放在字符串常量池中的"abc"对象
拼接问题二:
@Test
public void test2(){
String s1 = "my";
String s2 = "JavaBase";
String s3 = "myJavaBase";
String s4 = "my"+"JavaBase";
String s5 = s1 + "JavaBase";
String s6 = "my" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
String s8 = s5.intern();//获取常量池中的值
System.out.println(s3 == s8);//true
}
结论:
1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.字符串拼接中,只要有一个是变量,拼接后的对象就在堆中
3.如果拼接的结果调用intern()方法,返回值就在常量池中。
面试题:
public class StringTest2 {
String str = new String("abc");
char[] a = {'h','e','l','l','o'};
public void change(String str1,char[] a){
str1 = "test ok";
a[0] = 'b';
}
public static void main(String[] args) {
StringTest2 test = new StringTest2();
test.change(test.str,test.a);
System.out.println(test.str );//abc
System.out.println(test.a);//bello
}
}
分析:
1.在change方法中,值传递,str1变量获取到的是abc,再修改str1变量值,不会修改StringTest2.str的值
2.char[] a获取的是char[]的地址值,所以修改的是对中char[]对象的内容。