Java并发基础(二):如何实现一个不可变类?

x33g5p2x  于2021-09-19 转载在 Java  
字(3.0k)|赞(0)|评价(0)|浏览(480)

1、如何将一个类改造成不可变类?

将一个类改造成不可变类,来解决线程安全问题。

实现不可变类的一些思路:

使用final关键字修饰所有成员变量,避免其被修改,也可以保证多线程环境下被final关键字修饰的变量所引用的对象的初始化安全,即final修饰的字段在其他线程可见时,必定是初始化完成的。
1.
使用private修饰所有成员变量,可以防止子类及其他地方通过引用直接修改变量值。
1.
禁止提供修改内部状态的公开接口(比如我们前面例子中的setXY方法)
1.
使用final修饰类,禁止不可变类被外部继承,防止子类改变其定义的方法的行为。
1.
如果类中存在数组或集合,在提供给外部访问之前需要做防御性复制

防御性复制理解

  1. public final class DefensiveDemo {
  2. private final List<Integer> list = new ArrayList<Integer>();
  3. public DefensiveDemo(){
  4. list.add(1);
  5. list.add(2);
  6. list.add(3);
  7. }
  8. public List<Integer> getData(){
  9. return list;
  10. }
  11. public static void main(String[] args) {
  12. DefensiveDemo defensiveDemo = new DefensiveDemo();
  13. List<Integer> data = defensiveDemo.getData();
  14. data.add(4);
  15. }
  16. }

代码中能够对集合修改,不能保证不可变对象。

  1. public List<Integer> getData(){
  2. // return list;
  3. return Collections.unmodifiableList(new ArrayList<Integer>(list));
  4. }
  5. Exception in thread "main" java.lang.UnsupportedOperationException

使用Collections.unmodifiableList方法进行包装,这样能保证外部无法修改(添加元素)我们返回的结果,那么DefensiveReplicaDemo的data集合的值永远会是1,2,3。

防御性的深度拷贝

  1. public class DeepCopyObjectTest {
  2. public static void main(String[] args) {
  3. Map<Integer,Student> map = Maps.newHashMap();
  4. map.put(1,new Student("xiaoli",18));
  5. // copy(map);
  6. // deepCopy(map);
  7. baseCopy();
  8. }
  9. public static void copy(Map<Integer,Student> map){
  10. System.out.println(map.get(1).getName());
  11. Map<Integer,Student> newMap = Collections.unmodifiableMap(map);
  12. newMap.get(1).setName("xiaowang");
  13. System.out.println(map.get(1).getName());
  14. }
  15. public static void deepCopy(Map<Integer,Student> map){
  16. Map<Integer,Student> newMap = new HashMap<>(map.size());
  17. for (Map.Entry<Integer,Student> entry:map.entrySet()) {
  18. newMap.put(entry.getKey(),new Student(entry.getValue()));
  19. }
  20. newMap.put(2,new Student("xiaosun",20));
  21. Map<Integer,Student> result = Collections.unmodifiableMap(newMap);
  22. result.get(1).setName("xiaozhao");
  23. System.out.println(result.get(1).getName());
  24. System.out.println(map.get(1).getName());
  25. //Exception in thread "main" java.lang.UnsupportedOperationException
  26. //result.put(2,new Student("xiaosun",20));
  27. }
  28. public static void baseCopy(){
  29. Map<Integer,String> isMap = Maps.newHashMap();
  30. isMap.put(1,"a");
  31. isMap.put(2,"b");
  32. Map<Integer,String> isMapCopy = Collections.unmodifiableMap(isMap);
  33. // Exception in thread "main" java.lang.UnsupportedOperationException
  34. // isMapCopy.put(1,"aa");
  35. //Exception in thread "main" java.lang.UnsupportedOperationException
  36. // isMapCopy.put(3,"c");
  37. isMap.put(1,"aa");
  38. isMap.put(3,"c");
  39. System.out.println(isMap);//{1=aa, 2=b, 3=c}
  40. System.out.println(isMapCopy);//{1=aa, 2=b, 3=c}
  41. //== 是比较内存地址是否相同,equals 是比较内存地址上面的值是否相同
  42. System.out.println(isMap == isMapCopy);
  43. System.out.println(isMap.equals(isMapCopy));
  44. }
  45. }

unmodifiableMap理解

        返回指定有序映射的不可修改视图。此方法允许模块为用户提供对内部有序映射的“只读”访问。在返回的有序映射上执行的查询操作将“读完”指定的有序映射。试图修改返回的有序映射(无论是直接修改、通过其 collection 视图修改,还是通过其 subMap、 headMap或 tailMap视图修改)将导致抛出 UnsupportedOperationException。
就是说unmodifiableMap不能添加新的元素,并不能对基本类型进行修改。

Map<Integer,StringBuilder> unmodifiableMap=Collections.unmodifiableMap(map);

相关文章

最新文章

更多