標籤:技術分享 自己 long block 預設 pre nes ceo mod
Thinking in Java – 類型資訊
個人感覺 java 中的比較難的部分了,在看了些netty原始碼發現事實上這塊很實用。
這章重點是RTTI和反射。先說下自己的理解
RTTI是執行時識別。在c++中是用virtual來實現的,在編譯期會忽略對象的詳細類型資訊,假定我們已經知道,並在執行時詳細識別。
Java反射機制實在執行狀態中,對於隨意一個類,都能夠知道這個類的全部屬性和方法。對於隨意一個對象。都能夠調用它的隨意一個方法和屬性,這樣的動態擷取的資訊以及動態調用對 象的方法的功能稱為Java的反射機制
Class對象
Class對象就是用來建立類的全部的“常規”對象的。Java使用Class對象來執行其RTTI.
Class對象是什麼
Java是一門純物件導向的語言。在Java中,一切都是對象,也就是class,對於每一個類檔案(每一個對象)編譯後我們都會產生一個.class檔案(javac hello.java —> hello.class)。*.class檔案就是Class對象,在我們要第一次使用hello這個類檔案時。JVM的類載入器會來載入hello.class檔案,感覺Class對象就是一個模具。用來生產對象的。
注意:構造器也是靜態方法
範例:
package onefour_chapter;/** * Created by wwh on 15-8-7. */class Candy{ static { System.out.println("Loading Candy"); }}class Gum{ static { System.out.println("Loading Gum"); }}class Cookie{ static { System.out.println("Loading Cookie"); }}public class SweetShop { public static void main(String[] args){ System.out.println("inside main"); new Candy(); System.out.println("After creating Candy"); try{ Class.forName("Gum"); }catch (ClassNotFoundException e){ System.out.println("not found Gum"); } System.out.println("After Class.forName(\"Gum\")"); new Cookie(); System.out.println("After create Cookie"); }}
我執行完發現結果和書上不一致,原因是Class.forName()參數要求是全然限定名,My Code在包中。前面加上包名字就可以,例如以下
Class.forName(“包名.Gum”);
關鍵點:
static代碼塊
static修飾的代碼塊僅僅在類被載入時執行而且僅會被執行一次。一般用來初始化靜態變數和調用靜態方法,無論你new多少次,在jvm的聲明周期裡一個類僅僅被載入一次。
前面說構造器也是靜態方法,所以test t = new test(),在第一次建立對象時jvm就會載入test類的Class對象(.class檔案),Class對象就和其它對象一樣,我們能夠操控它的引用。forName()就是擷取Class對象引用的一種方法。
Class.forName()返回對象的Class引用,從Class對象中我們能夠獲得許多的資訊從而在執行時來抉擇一些事情。很像c++的type_traits。注意使用newInstance()創造的類必須帶有預設的構造器
static語句塊
static語句塊在類載入時執行。僅僅被執行一次
在用單例模式寫封裝資料庫連接池時,new一個資料庫連接池就被我寫在了static代碼塊中,保證在類載入時就初始化好串連池,且僅僅初始化一次。(注意。訪問靜態常量時。假設編譯器能計算出來。則不會載入)
類載入:在終端下Java載入.class檔案。Java命令的作用是啟動虛擬機器。虛擬機器通過流從磁碟上將位元組碼(.class檔案)中的內容讀入虛擬機器,並儲存起來的過程。
類字面常量
Java還提供了一種方法來產生Class對象的引用,即類字面常量,classname.class,比方hello.class。它更安全和高效也不用try語句包裹。所以一般我們不使用forName(),可用於類,介面,數組。基本類型。建議使用.class的形式。.class執行了“儘可能”懶惰初始化,而forName()馬上就初始化
為了使用類而做的準備工作有3個。載入–>串連–>初始化
範化的Class引用
Class引用總是指向某個Class對象,它能夠製造類的執行個體。並包括可作用於這些執行個體的全部方法代碼。它還包括該類的靜態成員,因此,Class參考資料表示的就是它所指向的對象的確切類型。該對象便是Class類的一個對象。
向Class引用加入範型文法原因僅僅是為了編譯器類型檢查。前面說了RTTI和反射都是執行時的。如今我們在編譯時間也做了一些限定。更加保證了執行的正確性
為了在使用範化的Class引用時放鬆限制。能夠使用了萬用字元,也但是使用萬用字元和extends關鍵字相結合。建立一個範圍。
Class
import java.util.ArrayList;import java.util.List;/** * Created by wwh on 15-8-7. */class CountedInteger{ static { System.out.println("Class 載入"); } private static long counter; private final long id = counter++; public String toString() { return Long.toString(id); }}public class FilledList<T> { private Class<T> type; /* 建構函式。參數為被限定的Class對象,我們能夠在執行個體化時來指定 */ public FilledList(Class<T> type){ this.type = type; } public List<T> create(int nElements){ List<T> result = new ArrayList<T>(); try{ for(int i = 0; i < nElements; i++){ result.add(type.newInstance()); } }catch (Exception e){ throw new RuntimeException(); } return result; } public static void main(String[] args){ /* 執行限定的類型,並傳遞.class作為建構函式的參數 */ FilledList<CountedInteger> fl = new FilledList<CountedInteger>(CountedInteger.class); System.out.println(fl.create(15)); }}
RTTI在Java中的第三種形式是instanceof,它返回一個布爾值,告訴我們對象是不是某個特定的執行個體。
if(obj instanceof Dog) obj.exe();
instanceof有比較嚴格的限制,僅僅能將其與命名類型進行比較。而不能與FClass對象作比較
Class.isInstance()方法提供了一種動態地測試對象的途徑。
Thinking in Java -- 類型資訊RTTI