String这个类比较特殊,因为底层final的
String 底层源码:
public final class String {
private final char value[];
}
因为String 底层是一个final的类,并且它底层的存储是一个char 类型的数组,也是一个final类型,也是说,从理论上面讲String 是一个不能更改的类。
前提:
JVM内存变量引用,以及对象,在内存中开辟的空间。
栈:存储是一个变量的引用,存储容量比较小的(二进制的地址码);
堆:当我们new 一个对象的时候,就会在堆中开辟一块空间,这块空间是由垃圾回收机制进行管理操作;
常量池:常量池这块也是在堆中。
静态域:放在堆里面
例如:
String a="he";
String b="llo";
String c="hello";
System.out.print(c==a+b); //false
final String a="he";
final String b="llo";
System.out.print(c==a+b) //true
System.out.print(c=="he"+“llo“) //true
System.out.print=(c==a+"llo") //false
解释:
1.首先 会在常量池中创建一个"he";然后在栈中创建一个 a ,然后b在常量池中创建一个"llo" 并且栈中的b指向常量池中"llo" ;
2.当a+b在编译的时候不会确定,所以c!=a+b 不相等,因为a+b 会在编译时候会调用toString 会new 一个新的对象,在堆中;
3.如果在a、b之前添加一个final则就会变为常量,然后在编译的时候就就会确定下来,所以就会相等,因为我们类加载的时候,要经过几个步骤,类准备、类加载,类初始化
在初始化的时候,系统就会自动的为一些,把这些常量直接宏替换到有用到这个常量的代码中了,简单来说就是(在初始化的时候就已经把值确定下来了)
也可以通过反射来改变String值
通过反射来获取值:
//创建字符串"Hello World", 并赋给引用s String s = "Hello World"; System.out.println("s = " + s); //Hello World //获取String类中的value字段 Field valueFieldOfString = String.class.getDeclaredField("value"); //改变value属性的访问权限 valueFieldOfString.setAccessible(true); //获取s对象上的value属性的值 char[] value = (char[]) valueFieldOfString.get(s); //改变value所引用的数组中的第5个字符 value[5] = '_'; System.out.println("s = " + s); //Hello_World }