蓝众建站_专业网站建设,专业seo推广,微信公众平台推广网站,xampp wordpress 慢String a “abc”; #xff0c;说一下这个过程会创建什么#xff0c;放在哪里#xff1f;
JVM会使用常量池来管理字符串直接量。在执行这句话时#xff0c;JVM会先检查常量池中是否已经存有abc#xff0c;若没有则将abc存入常量池#xff0c;否…String a “abc”; 说一下这个过程会创建什么放在哪里
JVM会使用常量池来管理字符串直接量。在执行这句话时JVM会先检查常量池中是否已经存有abc若没有则将abc存入常量池否则就复用常量池中已有的abc将其引用赋值给变量a。
new String(“abc”) 是去了哪里仅仅是在堆里面吗
由于String本身的不可变性后续分析在执行这句话时JVM会先使用常量池来管理字符串直接量即将abc存入常量池。接着使用new关键字在堆内存中创建一个String对象对象保存在堆中堆中对象的数据会指向常量池中abc字符串的引用。
如果再通过new String(“abc”)创建一个字符串对象此时由于字符串常量池已经存在abc所以只需要在堆内存中创建一个String对象即可。
intern 方法有什么作用?
String.intern() 是一个 native本地方法其作用是将指定的字符串对象的引用保存在字符串常量池中可以简单分为两种情况
如果字符串常量池中保存了对应的字符串对象的引用就直接返回该引用。如果字符串常量池中没有保存了对应的字符串对象的引用那就在常量池中创建一个指向该字符串对象的引用并返回。
具体案例举例及分析
// 在堆中创建字符串对象”Java“
// 将字符串对象”Java“的引用保存在字符串常量池中
String s1 Java;
// 直接返回字符串常量池中字符串对象”Java“对应的引用
String s2 s1.intern();
// 会在堆中在单独创建一个字符串对象
String s3 new String(Java);
// 直接返回字符串常量池中字符串对象”Java“对应的引用
String s4 s3.intern();
// s1 和 s2 指向的是堆中的同一个对象
System.out.println(s1 s2); // true
// s3 和 s4 指向的是堆中不同的对象
System.out.println(s3 s4); // false
// s1 和 s4 指向的是堆中的同一个对象
System.out.println(s1 s4); //trueString str1 “ab”;
String str2 “a” “b”;
//变量a和b都是常量字符串其中b这个变量在编译时由于不存在可变化的因素所以编译器会直接把变量b赋值为ab这个是属于编译器优化范畴也就是编译之后b会保存到Class常量池中的字面量。
//对于字符串常量初始化a时 会在字符串常量池中创建一个字符串ab并返回该字符串常量池的引用。
//对于变量b赋值ab时首先从字符串常量池中查找是否存在相同的字符串如果存在则返回该字符串引用。
System.out.print(str1 str2);//trueString str3 new String(Hello World); //创建对象对象指向常量池的Hello World“
String str4 str.intern();//str4指向常量池的Hello World“
System.out.println(str3 str4);//false引用的地址不一样一个在堆中一个在常量池中String str5 new String(Hello World) new String(!);//将Hello World和!都放在常量池但常量池没有Hello World!
String str6 str5.intern();//在常量池创建Hello World!即把str5放入常量池
System.out.println(str5 str6);//trueStringBuilder sb new StringBuilder().append(new String(Hello World)).append(new String(!));
String str7 sb.toString();
String str8 str.intern();//在常量池创建Hello World!即把str7放入常量池
System.out.print(str str1);//trueString s1 a;
String s2 b;
String s3 ab;
String s4 s1 s2; //等于StringBuilder sb new StringBuilder().append(s1).append(s2);
System.out.println(s3 s4);//false一个在常量池一个是StringBuilder的对象调用toString()方法
String的equals方法源码
public boolean equals(Object anObject) {if (this anObject) {//先判断地址地址一样一定相同return true;}if (anObject instanceof String) {//判断是不是String类型String anotherString (String)anObject;//是的话强转int n value.length;if (n anotherString.value.length) {//判断长度是否一致不一致直接falsechar 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 类型的变量和常量做“”运算时发生了什么两个字符串相加的底层是如何实现的
1.如果拼接的都是字符串直接量则在编译时编译器会将其直接优化为一个完整的字符串和你直接写一个完整的字符串是一样的。 对于编译期可以确定值的字符串也就是常量字符串 jvm 会将其存入字符串常量池。并且字符串常量拼接得到的字符串常量在编译阶段就已经被存放字符串常量池这个得益于编译器的优化。
常量折叠会把常量表达式的值求出来作为常量嵌在最终生成的代码中这是 Javac 编译器会对源代码做的极少量优化措施之一(代码优化几乎都在即时编译器中进行)。对于 String str3 str ing; 编译器会给你优化成 String str3 string; 。
并不是所有的常量都会进行折叠只有编译器在程序编译期就可以确定值的常量才可以
基本数据类型( byte、boolean、short、char、int、float、long、double)以及字符串常量。final 修饰的基本数据类型和字符串变量字符串通过 “”拼接得到的字符串、基本数据类型之间算数运算加减乘除、基本数据类型的位运算、、
引用的值在程序编译期是无法确定的编译器无法对其进行优化
2.如果拼接的字符串中包含变量则在编译时编译器采用StringBuilder对其进行优化即自动创建StringBuilder实例并调用其append()方法将这些字符串拼接在一起。
字符串使用 final 关键字声明之后可以让编译器当做常量来处理。
StringStringBuilderStringBuffer有什么区别
1.可变性
String 是不可变的后面会详细分析原因。
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类在 AbstractStringBuilder 中也是使用字符数组保存字符串不过没有使用 final 和 private 关键字修饰最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的方法比如 append 方法。
abstract class AbstractStringBuilder implements Appendable, CharSequence {char[] value;public AbstractStringBuilder append(String str) {if (str null)return appendNull();int len str.length();ensureCapacityInternal(count len);str.getChars(0, len, value, count);count len;return this;}//...
}2.线程安全性
String 中的对象是不可变的也就可以理解为常量线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类定义了一些字符串的基本操作如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁所以是线程安全的。StringBuilder 并没有对方法进行加同步锁所以是非线程安全的。
3.性能
每次对 String 类型进行改变的时候都会生成一个新的 String 对象然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升但却要冒多线程不安全的风险。
对于三者使用的总结
操作少量的数据: 适用 String单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer