java基础---不可变对象创建
通过反射还是可以修改的。
public static void stringReflection() throws Exception {
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//获取String类中的value字段
Field valueField = String.class.getDeclaredField("value");
//改变value属性的访问权限
valueField.setAccessible(true);
char[] value = (char[]) valueField.get(s);
//改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
}
===为什么string是不可变对象,有什么优势?
底层使用private final char value[];有一个private final的数组
1.节省堆空间,string对象创建后会存入字符串常量池中,同一个string可以有不同的指针同时指向。
保证唯一性,多线程处理同一个string的时候不用担心线程问题,因为不可变。
2.安全性考虑。
---数据库账号密码
---网络编程的端口号和ip
---类加载器加载类的时候
都是通过string来传递,如果可变会造成系统漏洞
3.用于当hashmap的键特别适合,因为hashcode不变不需要重复计算,直接缓存这个hashcode
===如何创建一个不可变类?
简述:成员变量是private final类型,初始化用构造函数克隆的方式初始化,没有set方法,get方法使用克隆的方式进行访问。
---类定义:final修饰类,不能够继承
---成员变量:1.成员变量设为私有private final,通过构造器初始化;2.不为成员变量设置set方法;3.如果有可变对象那么初始化的时候必须使用clone的方式进行初始化,新建一个对象初始化,否则会影响到原有的对象。
---方法:1.对于不可变对象中的可变对象的访问方式:比如说有个map,那么如何获取呢?get方法不能够直接返回对象本身,而是通过克隆来返回对象,这样修改原始数据不会影响新建的这个数据。2.同时构造器进行初始化对象的时候必须创建一个新的hashmap来复制构造函数的入参map,就是克隆
目的:比如我有三个属性int,string,hashmap用来初始化了一个不可变对象,那么我获取到对象中的hashmap的引用,获取引用使用hasmap.clone()方法,那么这个引用指向新的数组地址,但是如果hashmap内部有对象引用的话,是不会进行复制的,还是指向了原有的对象。
===hashmap的clone方法是深拷贝还是浅拷贝呢?
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
这个是entry克隆的内部实现,键值对都会进行新建。
如果是引用类型的时候,只是复制了引用,所以修改新的或者旧的引用的时候都是指向同一个堆空间中的对象的。
1.HashMap的clone方法生成新的对象,新的对象有自己独立的存储空间。
2.虽然HashMap的clone方法生成了新的对象,但新的HashMap和原来的HashMap所存储的引用类型都是指向的同一存储空间。
这就导致在对HashMap中的元素进行修改的时候,即对数组中元素进行修改,会导致原对象和clone对象都发生改变,但进行新增或删除就不会影响对方,因为这相当于是对数组做出的改变,clone对象新生成了一个数组。