String是被final修饰的 这个应该没啥好说的 所以String修饰的全部是常量。那么可能有的小伙伴们就要问了 我先Stirng x="123" 然后 x="456" 在输出x的值还是456啊  这不是变了吗 其实Java内部有个常量池 栈内存中的x先指向常量池内的123 然后又把x指向了456,123在常量池中还是存在的 只不过变成了垃圾 会由GC进行不定时回收,一开始定义了123那么123就是不可更改的 可以更改的只是x所指向的地址值。就像找老婆一样 你可以选择找小A或者小B当你的老婆 你可以自己选择指向A或者B 但是小A小B本身是不可变的。 

然后下面我们再来看一段代码


String s1 = "abc";
String s2 = "ab";
String s3 = "c";
String s4 = "ab"+"c";
String s5 = s2+s3;
System.out.println(s1==s4);    //true
System.out.println(s1==s5);   //false
System.out.println("s1==s4"+s1==s4);   //false
System.out.println("s1==s4:"+(s1==s4));   //s1==s4:true


如果这些题目你都可以完全答对的话 那么恭喜你 你对String的掌握应该到了一定的程度了 下面来详细说明一下

s1比较s4 因为s4是由字符串拼接而成 Java内部常量池在创建s4发现之前在创建s1的时候有abc这个字符串 所以就直接让s4指向s1的地址值 所以为true

s1比较s5 其中s5是由s2和s3拼接而成 其内部是用了StringBuilder 相当于new了一下 虽然数值一样 但是地址值已经变化吗,如果不是用== 而是用equals 那么输出的结果为true 这也说明了==比较的是地址值 而equals比较的是具体数值(PS:这只是基本数据类型和字符串中是这样 比较对象的话两者并没有区别)

至于第三行就涉及到优先级的问题了 +号比==优先级要高 这样的语句是先比较s1==s4 + s1 在和s4比较 当然为false 这个反过来


System.out.println(s1==s4+"s1==s4");结果也是false


第四行就是反其道而行之 用括号括起来就是先计算括号里的内容 输出是s1==s4:true 而不仅仅只是一个true 

这些说完了就在说说String直接等号赋值与new出来的区别吧 话不多说 咱们在弄两个栗子


String a = "123";
String b = new String("123");

String c= new String("456");
String d= "456";
System.out.println(a==b); //false
System.out.println(c==d); //false


直接new出来的与==的区别在哪呢  直接==的话是如果"123" 这个字符串在java String池中不存在 会在java String池中创建一个String a= "123"的对象 然后把a指向这个内存地址  而new的话出来的都是在堆内存中  如果123在常量池内不存在 那么就会在常量池中创建一个。总结:==号可能会创建一个对象 也可能不会创建 new的话至少会创建一个对象 可能会创建两个

说完了这些咱们再来聊聊为啥String要被final修饰呢 这样有什么好处吗 

其实String不可变的好处主要就是安全性考虑 因为不可变所以在多线程下也是安全的 同一个String可以被多个线程所共享 并且链接数据库的时候 账号密码都是以String形式传入的 不可变会确保安全 并且维持字符串常量池的必备条件就是不可变 因为引用的都是地址值 这样可以节省内存空间的作用 其次的话可以让String对象缓存hashcode 可以把计算过后的hashcode用String进行缓存  从而不用多次计算