java中Final關鍵字和Immutable Class以及Guava的不可變對象

大綱

  1. 寫這篇文章的原由html

  2. java中Final關鍵字java

  3. 如何構建不可變對象app

  4. Guava中不可變對象和Collections工具類的unmodifiableSet/List/Map/etc的區別ide

  5. 實驗代碼
    函數

寫這篇文章的原由

    java項目在使用FindBugs掃描的時候報了一個不能使用可變對象,記得報的是相似以下的信息:工具

MS: Field is a mutable collection (MS_MUTABLE_COLLECTION)
官方解釋:
A mutable collection instance is assigned to a final static field, thus can be changed by malicious code or by accident from another package. Consider wrapping this field into Collections.unmodifiableSet/List/Map/etc. to avoid this vulnerability.

參考FindBugs的描述:http://findbugs.sourceforge.net/bugDescriptions.html

因爲最近學習的東西較多,對有些基本的概念略有生疏,因此又溫故了一下,順便提供下上面問題的解決方案,僅供參考。
性能

java中Final關鍵字

    Final是java的一個關鍵字,能夠修飾:變量、方法、類,大體用法,我寫了一個測試類,註釋也比較多。學習

package org.unrulylianzi.basis.javass.finalkeyword;


/**
 * java final 基本用法
 * <li>variable</li>
 * <li>method</li>
 * <li>class</li>
 * */
public class JavaFinalKeyWord {
	/**
	 * 基本類型
	 * */
	private final int a=3;
	
	private final int b;//must be initialized at the time of declaration or inside constructor or block

	
	{
		//a=4;不能重複對final的變量賦值
		System.out.println(a);
		b=4;
	}

	/**
	 * 引用類型
	 * */
	private final Person person = new Person("unrulylianzi");//must be initialized at the time of declaration or inside constructor
	
	{
		//person = new Person("unrulylianzi_change_final");//不能重複對final的變量賦值
		System.out.println(person);
		
		person.setName("unrulylianzi_change_value_not_reference");//能夠修改引用類型的值,可是不能賦予新的Person對象
		
		System.out.println(person);
	}
	/**
	 * method
	 * */
	
	public  final String finalMethod(){
		return "unrulylianzi_final";
	}
	
	/**
	 * method not final
	 * */
	
	public  String notFinalMethod(){
		return "unrulylianzi_notfinal";
	}
}

final class  SubClass extends JavaFinalKeyWord {

	@Override
	public String notFinalMethod() {
		// TODO Auto-generated method stub
		return super.notFinalMethod();
	}
	
	/**
	 * final method can not be  overridden in Java
	   final的方法不能被繼承
	@Override
	public String finalMethod() {
		// TODO Auto-generated method stub
		return super.finalMethod();
	}
	*/
	
}

/**
 *
 *Final class can not be inheritable in Java.
 Final修飾的類不能被繼承

class ExtendsFinalClass extends SubClass {
	
}

*/

其中Person類是一個簡單的bean
public class Person {
	private String name;
	//getter&setter
}

固然Final對性能也有不少好處,此次不會講到。測試

如何構建不可變對象

    這個問題貌似沒太在乎過,也沒深刻思考過Final關鍵字和Immutable對象之間的關係。不可變對象就是對象一旦建立就是不能被改變的。下面列一下建立不可變類的步驟this

  • 聲明class爲Final,以避免class被子類繼承,關於多態的概念就不講啦。

  • 把全部類的屬性聲明成private,而且不提供set方法。

  • 把全部可變的變量聲明爲Final,使得這些變量只能初始化一次。

  • 暴露給外部的構造函數,在賦值的時候,要使用深拷貝。

  • 在變量對應的get方法的時候要提供引用類型變量的clone,而不是直接返回。

    我建立的一個不可變對象的示例代碼以下:

package org.unrulylianzi.basis.javass.immutable;

import java.util.HashMap;
import java.util.Iterator;

/**
 * 不變對象
 * <li>1:Declare the class as final so it can’t be extended.</li>
 * <li>2:Make all fields private so that direct access is not allowed.</li>
 * <li>3:Don’t provide setter methods for variables</li>
 * <li>4:Make all mutable fields final so that it’s value can be assigned only once.</li>
 * <li>5:Initialize all the fields via a constructor performing deep copy.</li>
 * <li>6:Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference.</li>
 * */

public final class ImmutableClass {
	
	
	private final int age;
	private final String name;
	
	private final HashMap<String,String> testMap;

	/**
	 * shallow copy
	 * */
//	public ImmutableClass(int age, String name, HashMap<String, String> testMap) {
//		super();
//		this.age = age;
//		this.name = name;
//		this.testMap = testMap;
//	}
	
	/**
	 * deep copy
	 * */
	public ImmutableClass(int age, String name, HashMap<String, String> testMap) {
		super();
		this.age=age;
		this.name=name;
		HashMap<String,String> tempMap=new HashMap<String,String>();
		String key;
		Iterator<String> it = testMap.keySet().iterator();
		while(it.hasNext()){
			key=it.next();
			tempMap.put(key, testMap.get(key));
		}
		this.testMap=tempMap;
	}

	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	public HashMap<String, String> getTestMap() {
		//return testMap
		return (HashMap<String, String>) testMap.clone();
	}
	
}

可見Final關鍵字是建立不可變對象的基礎。

Guava中不可變對象和Collections工具類的unmodifiableSet/List/Map/etc的區別

    guava是google的一個庫,彌補了java語言的不少方面的不足,不少在java8中已有實現,暫時不展開。Collections是jdk提供的一個工具類。二者之間的區別:

當Collections建立的不可變集合的wrapper類改變的時候,不可變集合也會改變,而Guava的Immutable集合保證確實是不可變的。

     測試代碼以下:

//guava的實現
public static final List<String> immutableList;

	static {
		immutableList = ImmutableList.of("a");
	}

	/**
	 * 改變immutableList
	 * 
	 */
	public static void immutableListGuavaChange() {

		try {
			System.out.println("Try adding more elements to ImmutableList");
			/**
			 * 改變immutableList已存在元素的值,添加新的元素,都會報錯,拋出異常
			 */
			immutableList.set(0, "b");
			// immutableList.add("b");
		} catch (UnsupportedOperationException e) {
			System.out.println(
					"Throws UnsupportedOperationException, ImmutableList is immutable, won't allow adding elements");
		}
	}

  Collections工具類的實現:

/**
 * Collections工具類實現的不可變list的示例
 */
public class ImmutableListCollections {

	public static final Collection unmodifiableList;
	public static final List list;

	static {
		list = Arrays.asList("Once", "upon", "time", "there", "used", "to", "be", "king");
		unmodifiableList = Collections.unmodifiableCollection(list);
	}

	/**
	 * 改變immutableList
	 * 
	 */
	public static void immutableListCollectionsChange() {

		System.out.println("Try adding more elements to ImmutableList");
		/**
		 * 改變unmodifiableList已存在元素的值,添加新的元素,都會報錯,拋出異常
		 */
		list.set(0, "b");
		System.out.println("###修改wrapper類###" + unmodifiableList);
		// immutableList.add("b");

	}
}

Guava和Collections實現原理(只爲說明不可變,未深刻)

查看Guava和Collections的實現,發現add方法是以下設計的:

public final void add(int index, E element) {
  throw new UnsupportedOperationException();
}

一、定義Final,防止子類改變父類的行爲。

二、執行修改操做的時候,直接拋異常。

實驗代碼

相關文章
相關標籤/搜索