在讲String 和 new String 的区别之前先看一段代码:
String a = "ss"; String b = "ss"; String c = new String("ss"); System.out.println(a==c); System.out.println(a.equals(b)); 最终输出结果
false
true
还需要知道的String 类型 的声明类型,查看源码可以知道
这个时候我们就知道原来String 是被final修饰,代表不可变的字符序列,且创建出来的字符串是存放在常量池里面,也就存在于方法区中。(此处关于字符串常量池存放位置,这个是根据jdk版本不同而不同的,此处举例在方法区中。)
那么每一次执行 String a="aa"; String b = "aa"; “aa”被存放在常量池中,当引用b(位于栈)被创建的时候发现“aa”在常量池已经存在,jvm会把b引用指向"aa",
而new String()可以分类俩个阶段
1. 在编译阶段JVM先去常量池中查找是否存在“abc”,如果过不存在,则在常量池中开辟一个空间存储“abc”。
2. 在运行时期,通过String类的构造器在堆内存中new了一个空间,然后将String池中的“abc”复制一份存放到该堆空间中,在栈中开辟名字为str2的空间,存放堆中new出来的这个String对象的地址值。
所以这个时候返回看上面的代码就很简单啦
a 和 b 指向的是位于常量池中的同一块地址,当然结果是true啦
a 和 c 相比,c指向是堆内存“aa”存在的地址,a指向常量池的地址,所以是false;
2. 关于String 拼接比较的问题
先看代码~
public class Test{ public static void main(String[] args){ String str = "helloworld"; String str1 = "hello"; String str2 = "world"; String str3 = "hello" + "world"; String str4 = "hello" + str2; String str5 = str1 + "world"; System.out.println(str1 == str2); //false System.out.println(str == str3); //true System.out.println(str == str4); //false System.out.println(str == str5); //false System.out.println(str4 == str5); //false } }
<1、常量与常量的拼接结果在常量池中。且常量池中不会存在相同内容的常量
<2、常量与常量拼接时,只要其中有一个是变量 ,结果就在堆中
<3、使用相同的字符序列而不是使用new关键字创建的两个字符串会创建指向Java字符串常量池中的同一个字符串的指针。
根据final 引申出来的一个问题,final修饰的 变量不能被修改,那反射能修改变量么?
这个时候要分俩种情况
1. 当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了。
2. 当final修饰的成员变量在定义的时候并没有初始化值的话,那么就还能通过java反射机制来动态修改它的值。
参考链接:https://blog.csdn.net/qq_33417486/article/details/82787598