不可变对象
共享对象想要安全发布,主要有两种方法,一种是额外同步的方法,另外则是将对象做为不可变对象。当满足一下条件时,对象才是不可变的:
- 对象创建以后其状态就不能修改
- 对象所有的域都是final类型
- 对象正确创建(在创建对象期间,this引用没有逸出)
安全发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见,一个正确构造的对象可以通过以下方式安全发布:
- 在静态初始化函数中初始化一个对象引用
- 将对象的引用保存到volatile类型的域或AutomicReference对象中
- 将对象的引用保存到某个正确构造对象的final类型域中
- 将对象的引用保存到一个锁保护的域中
不可变对象具体:
- Declare the class as final so it can’t be extended.
- Make all fields private so that direct access is not allowed.
- Don’t provide setter methods for variables
- Make all mutable fields final so that it’s value can be assigned only once.
- Initialize all the fields via a constructor performing deep copy.
- Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference.
例子:
package com.journaldev.java; import java.util.HashMap; import java.util.Iterator; public final class FinalClassExample { private final int id; private final String name; private final HashMap<String,String> testMap; public int getId() { return id; } public String getName() { return name; } /** * Accessor function for mutable objects */ public HashMap<String, String> getTestMap() { //return testMap; return (HashMap<String, String>) testMap.clone(); } /** * Constructor performing Deep * @param i * @param n * @param hm */ public FinalClassExample(int i, String n, HashMap<String,String> hm){ System.out.println("Performing Deep for Object initialization"); this.id=i; this.name=n; HashMap<String,String> tempMap=new HashMap<String,String>(); String key; Iterator<String> it = hm.keySet().iterator(); while(it.hasNext()){ key=it.next(); tempMap.put(key, hm.get(key)); } this.testMap=tempMap; } /** * Constructor performing Shallow * @param i * @param n * @param hm */ /** public FinalClassExample(int i, String n, HashMap<String,String> hm){ System.out.println("Performing Shallow for Object initialization"); this.id=i; this.name=n; this.testMap=hm; } */ /** * To test the consequences of Shallow and how to avoid it with Deep for creating immutable classes * @param args */ public static void main(String[] args) { HashMap<String, String> h1 = new HashMap<String,String>(); h1.put("1", "first"); h1.put("2", "second"); String s = "original"; int i=10; FinalClassExample ce = new FinalClassExample(i,s,h1); //Lets see whether its copy by field or reference System.out.println(s==ce.getName()); System.out.println(h1 == ce.getTestMap()); //print the ce values System.out.println("ce id:"+ce.getId()); System.out.println("ce name:"+ce.getName()); System.out.println("ce testMap:"+ce.getTestMap()); //change the local variable values i=20; s="modified"; h1.put("3", "third"); //print the values again System.out.println("ce id after local variable change:"+ce.getId()); System.out.println("ce name after local variable change:"+ce.getName()); System.out.println("ce testMap after local variable change:"+ce.getTestMap()); HashMap<String, String> hmTest = ce.getTestMap(); hmTest.put("4", "new"); System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap()); } }