訪問的問題
如果缺少良好的訪問控制會使線程編程非常困難大多數情況下如果能保證線程只從同步子系統中調用不必考慮線程安全(threadsafe)問題我建議對 Java 編程語言的訪問權限概念做如下限制應精確使用 package 關鍵字來限制包訪問權我認為當缺省行為的存在是任何一種計算機語言的一個瑕疵我對現在存在這種缺省權限感到很迷惑(而且這種缺省是包(package)級別的而不是私有(private))在其它方面Java 編程語言都不提供等同的缺省關鍵字雖然使用顯式的 package 的限定詞會破壞現有代碼但是它將使代碼的可讀性更強並能消除整個類的潛在錯誤 (例如如果訪問權是由於錯誤被忽略而不是被故意忽略) 重新引入 private protected 它的功能應和現在的 protected 一樣但是不應允許包級別的訪問 允許 private private 語法指定實現的訪問對於所有外部對象是私有的甚至是當前對象是的同一個類的對於左邊的唯一引用(隱式或顯式)應是 this 擴展 public 的語法以授權它可制定特定類的訪問例如下面的代碼應允許 Fred 類的對象可調用 some_method() 但是對其它類的對象這個方法應是私有的
這種建議不同於 C++ 的 friend 機制 在 friend 機制中它授權一個類訪問另一個類的所有 私有部分在這裡我建議對有限的方法集合進行嚴格控制的訪問用這種方法一個類可以為另一個類定義一個接口而這個接口對系統的其余類是不可見的
除非域引用的是真正不變(immutable)的對象或static final 基本類型否則所有域的定義應是 private 對於一個類中域的直接訪問違反了 OO 設計的兩個基本規則抽象和封裝從線程的觀點來看允許直接訪問域只使對它進行非同步訪問更容易一些
增加$property 關鍵字帶有此關鍵字的對象可被一個bean 盒應用程序訪問這個程序使用在 Class 類中定義的反射操作(introspection) API否則與 private private 同效 $property 屬性可用在域和方法這樣現有的 JavaBean getter/setter 方法可以很容易地被定義為屬性
不變性(immutability)
由於對不變對象的訪問不需要同步所以在多線程條件下不變的概念(一個對象的值在創建後不可更改)是無價的Java 編程言語中對於不變性的實現不夠嚴格有兩個原因對於一個不變對象在其被未完全創建之前可以對它進行訪問這種訪問對於某些域可以產生不正確的值 對於恆定 (類的所有域都是 final) 的定義太松散對於由 final 引用指定的對象雖然引用本身不能改變但是對象本身可以改變狀態
第一個問題可以解決不允許線程在構造函數中開始執行 (或者在構造函數返回之前不能執行開始請求)
對於第二個問題通過限定final 修飾符指向恆定對象可以解決此問題這就是說對於一個對象只有所有的域是 final並且所有引用的對象的域也都是 final此對象才真正是恆定的為了不打破現有代碼這個定義可以使用編譯器加強即只有一個類被顯式標為不變時此類才是不變類
有了$immutable 修飾符後在域定義中的 final 修飾符是可選的
最後當使用內部類(inner class)後在 Java 編譯器中的一個錯誤使它無法可靠地創建不變對象
既使空的 final 在每個構造函數中都有初始化還是會出現這個錯誤信息自從在 版本中引入內部類後編譯器中一直有這個錯誤在此版本中(三年以後)這個錯誤依然存在現在該是改正這個錯誤的時候了
對於類級域的實例級訪問
除了訪問權限外還有一個問題即類級(靜態)方法和實例(非靜態)方法都能直接訪問類級(靜態)域這種訪問是非常危險的因為實例方法的同步不會獲取類級的鎖所以一個synchronized static 方法和一個 synchronized 方法還是能同時訪問類的域改正此問題的一個明顯的方法是要求在實例方法中只有使用 static 訪問方法才能訪問非不變類的 static 域當然這種要求需要編譯器和運行時間檢查
由於f() 和 g() 可以並行運行所以它們能同時改變 x 的值(產生不定的結果)請記住這裡有兩個鎖 static 方法要求屬於 Class 對象的鎖而非靜態方法要求屬於此類實例的鎖
或則編譯器應獲得讀/寫鎖的使用
另外一種方法是(這也是一種理想的 方法) 編譯器應 自動 使用一個讀/寫鎖來同步訪問非不變 static 域這樣程序員就不必擔心這個問題
[] [] [] [] [] [] []
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27688.html