一、创建String对象的两种方式
- 直接赋值
- new
//1.直接使用赋值方法获取一个字符串对象
String s1 = "abc";
System.out.println(s1); //abc
//2.使用new的方式来获取一个字符串对象
//空参构造:可以获取一个空白字符串对象
String s2 = new String();
System.out.println("a"+s2+"b"); //ab s2=""
//3.传递一个字符串,根据传递的字符串内容再创建一个新的字符串对象
String s3 = new String("abc");
System.out.println(s3); //abc
//4.传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
char[] chs={'a','b','c','d'};
String s4 = new String(chs);
System.out.println(s4); //abcd
//5.传递一个字节数组,根据字节数组的内容在创建一个新的字符串对象
byte[] bytes={95,96,97,98,99};
String s5 = new String(bytes);
System.out.println(s5); //abcd
二、不同创建对象方式的内存区别
字符串池(StringTable)是存在于堆中的一块区域(JDK1.7之后串池从方法区移动到了堆内存中。)
1.直接赋值
public class MainApp{
public static void main(String[] args){
String s1="abc";
String s2="abc";
}
}
当使用双引号直接赋值时,系统会检查该字符串在串池中是否存在。
例如上文的代码段,对s1赋值时,在串池中未找到"abc"字符串,于是新建一个,当对s2赋相同值时,在串池中找到了该值,于是就将该值的地址直接给到s2。
不存在:创建新的
存在:复用
2.new
public class MainApp{
public static void main(String[] args){
char[] chs = {'a','b','c'};
String s1 = new String(chs);
String s2 = new String(chs);
}
}
每new一次就开辟了一个新的内存空间。
三、String字符串比较方法
1.==号
String s1 = "abc";
String s2 = "abc";
String s3 = "aaa";
System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
==号比较的是什么?
比较基本数据类型
int a = 10; int b = 20; System.out.println(a==b);//false
基本类型比较的是数据值。
引用数据类型
String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1==s2);//false
引用数据类型比较的是地址值。
思考:
String s1 = new String("abc");
String s2 = "abc";
Syetem.out.println(s1==s2);//true or false ?
只要new出来的就在实在堆里开辟的空间,而s2记录的为StringTable串池里的内容。
Scanner sc = new Scanner(System.in);
String s1 = sc.next(); //abc
String s2 = "abc"
System.out.println(s1==s2); //false
这里为false的原因与上面相同,通过键盘输入获取的字符串也相当于new出来的,其地址存在堆内存中,而"=="比较的是地址值,所以返回false
2.equals方法
boolean equals()
比较的两个值完全一样为true,否则为falseboolean equalsIgnoreCase()
忽略两个比较值的大小写后再进行比较
四、StringBuilder
static void test1(){
String s ="";
long timeAgo=System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
s = s + "abc";
}
long timeNow=System.currentTimeMillis();
System.out.println("test1执行耗时"+(timeNow-timeAgo)+"ms");
}
static void test2(){
StringBuilder s=new StringBuilder();
long timeAgo=System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
s.append("abc");
}
long timeNow=System.currentTimeMillis();
System.out.println("test2执行耗时"+(timeNow-timeAgo)+"ms");
}
写出上面两个方法,对字符串s不断拼接1000000个“abc”,一个使用s+="abc",另一个使用StringBuilder类中的append()方法。
打印结果为
test1执行耗时138645ms
test2执行耗时39ms
StringBuilder可以看作一个容器,创建后里面的内容可变。
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = "d";
String s5 = "e";
String s6 = s1+s2+s3+s4+s5;
当运行上面代码段时,s1和s2首先会拼接成一个新的字符串,然后用新的字符串再跟s3拼接...整个拼接过程中生成了很多无用的字符串,每个字符串都在StringTable串池中开辟了新的地址,非常影响内存。
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");
sb.append("e");
当通过StringBuilder拼接字符串时不会产生无用字符串,始终在一个地址值上对字符串进行拼接。