Write once,Runanywhere.
如果你觉得我的文章有帮助到你,还请【关注➕点赞➕收藏】,得到你们支持就是我最大的动力!!!
⚡版权声明:本文由【马上回来了】原创、在CSDN首发、需要转载请联系博主。
版权声明:本文为CSDN博主「马上回来了」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
新的知识开始喽
下面创建String对象的方式相同吗?
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
System.out.println(s3==s4);//false
}
为什么s1和s2引用的是同一个对象,而s3和s4引用的不是同一个对象呢?
对于1,3.14,"hello"这种被经常使用的字面常量,为了使程序运行跟块,跟节省空间,Java为这8中数据类型和String类型提供了常量池。
字符串常量池在JVM中是StringTable类,实际是一个固定大小HashTable(一种高效用来进行查找的数据结构,后序给大家详细介绍),不同JDK版本下字符串常量池的位置以及默认大小是不同的,其中Java8 在堆中。
此处在java8上分析
对于直接使用常量创建String类:
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1==s2);//true
}
直接new常量池一开始没有的对象:
public static void main(String[] args) {
String s1 = new String("world");
}
public static void main(String[] args) {
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3==s4);//false
}
intern方法是一个native方法(native方法是指底层用C++实现的,看不到它的源代码)该方法的作用是手动将创建的String对象添加到常量池中。
public static void main(String[] args) {
char[] chars = {'a','b','c'};
String s1 = new String(chars);
//s1.intern();
String s2 = "abc";
System.out.println(s1==s2);//未使用intern方法 false
}
先看这两行代码:
//字符数组转字符串
char[] chars = {'a','b','c'};
String s1 = new String(chars);
这两行代码执行的结果:
这两行代码执行的过程:
一直到到这两行代码执行结束,常量池都没有添加双引号"“引起的字符串常量,因为s1里没有”"引起的字符串。
整个代码执行完毕:
当执行intern方法时:
public static void main(String[] args) {
char[] chars = {'a','b','c'};
String s1 = new String(chars);
s1.intern();
String s2 = "abc";
System.out.println(s1==s2);// true
}
public static void main(String[] args) {
char[] chars = {'a','b','c'};
String s1 = new String(chars);
//运行到这里s1不在常量池中
//s2在常量池中
String s2 = "abc";
//intern检查常量池,发现常量池里有"abc",不会再将s1引用的对象放入到常量池里,因此这里结果跟没有使用intern方法的情况类似。
s1.intern();
System.out.println(s1==s2);// false
}
JDK1.8中
String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
为什么 String 要涉及成不可变的?(不可变对象的好处是什么?) (选学)
public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); //并不是在原有的hello空间上接了一个world,而是产生了一个新对象输出:hello world,
}
2.注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。效率低下的原因是因为每次对字符串拼接都会产生新的对象。
下面是String类、StringBuilder类和StringBuffer类分别执行一段代码,StringBuilder类和StringBuffer类的效率是String类的282倍。
public static void main(String[] args) {
//String
long start = System.currentTimeMillis();
String s = "";
for(int i = 0; i < 10000; ++i){
s += i;
}
long end = System.currentTimeMillis();
System.out.println(end - start);//282
//StringBuffer
start = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer("");
for(int i = 0; i < 10000; ++i){
sbf.append(i);
}
end = System.currentTimeMillis();
System.out.println(end - start);//1
//StringBuilder
start = System.currentTimeMillis();
StringBuilder sbd = new StringBuilder();
for(int i = 0; i < 10000; ++i){
sbd.append(i);
}
end = System.currentTimeMillis();
System.out.println(end - start);//1
}
再看这个代码:
public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); //并不是在原有的hello空间上接了一个world,而是产生了一个新对象输出:hello world,
}
我们看看这段代码的汇编:
我们已经知道了:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。
现在用StringBuilder来还原这段汇编码:
append方法:
StringBuilder s1 = new StringBuilder();
s1.append("hello");
s1.append("hello");
String s = s1.toString();
System.out.println(s);//hellohello
代码执行过程看动图:
当然也可以使用StringBuffer来实现:
StringBuffer s1 = new StringBuffer();
s1.append("hello");
s1.append("world");
String s = s1.toString();
System.out.println(s);
使用StringBuilder与StringBuffer的区别:
面试题:
String str = new String("ab"); // 会创建多少个对象 2
String str = new String("a") + new String("b"); // 会创建多少个对象 2 + 2 + 2(new StringBuilde)、(new toString)
今天的你看懂这里又学到了很多东西吧
下次见喽