《Java編程思想》之類型檢查(RTTI與反射機制)

1、類型時類型識別(run-timetype identification,RTTI):當之有一個指向對象的引用時,RTTI可以讓你找出這個對象的確切類型。

2、Java運行時識別對象和類的信息,主要有倆種方式:

1).一種是“傳統“RTTI,它假定我們在運行時已經知道了所有的類型。

2).另一種是“放射“機制,它允許我們在運行時獲得類的信息。

3、Class對象:每個類都有一個Class對象,保存在一個同名的.class文件中,它包含了與類相關的信息。

4、在運行時,當我們想生成這個類的對象時,運行這個程序的Java虛擬機(JVM)首先檢查這個類的Class對象是否已經加載,就會根據類名查找.class文件,並將其載入。所以Java並非一開始執行就完全加載的,這一點與許多傳統語言都不同。        

5、Class.forName(“類名”)是獲得Class引用的一種方法,該方法返回一個Class對象的引用。例如:Class.forName(“MyClass”);

在調用該方法時,若MyClass類被還沒加載,則加載MyClass類。

6、類字面常量:另一種獲得Class引用的方法,MyClass.class(類名.class)。

此方法,更安全,更高效。

7、類字面常量不僅應用於普通的類,也可以應用於接口、數組以及基本數據類型。

8、RTTI的形式包括:

1).傳統的類型轉化。如Base類是Subclass類基類。

Base base = new Subclass();
Subclass sub= (Subclass)base;//(Subclass),由RTTI確定類型轉化正確性。在C++中,經典的類型轉換“(Subclass)”並不使用RTTI。

2).代表對象的類型的Class對象。同過查詢Class對象可以獲取運行時所需的信息。

3).RTTI的第三種形式,使用關鍵字“instanceof”。如:

boolean yesOrNot = (base instanceof Subclass);

若base是Subclass類的實例,yesOrNot就爲true

9、instanceof與Class的等價性:

class Base{}
class Subclass extends Base{};
public class Test{
   static void test(Object x){
      System.out.println("Testing x of type: " + x.getClass());
      System.out.println("x instanceof Base: " + (x instanceof Base));
      System.out.println("x instanceof Subclass: " + (x instanceof Subclass));
      System.out.println("Base.isInstance(x): " + (Base.class.isInstance(x)));
      System.out.println("Subclass.isInstance(x):" + (Subclass.class.isInstance(x)));
      System.out.println("x.getClass() == Base.class: " + (x.getClass() == Base.class));
      System.out.println("x.getClass() == Subclass.class: " + (x.getClass() == Subclass.class));
      System.out.println("x.getClass().equals(Base.class): " + (x.getClass().equals(Base.class)));
      System.out.println("x.getClass().equals(Subclass.class): " + (x.getClass().equals(Subclass.class)));
   }
   public static void main(String[] args){
      test(new Base());
   System.out.println("---------------------------------------------------");
      test(new Subclass());
   }
}

運行結果:


1).instanceof 與 isInstance生成的結果完全一樣,equal與==也一樣。

2). Instanceof與isInstance保持了類型的概念,它指得是“你是這個類,或者是這個類的派生類嗎?”

3).equal與==比較實際的Class對象,沒有考慮繼承。

10、Java是通過Class對象來實現RTTI機制的,即使我們只是做些諸如類型轉換這類的事情。Class類提供的一些方法:


11、RTTI的限制:編譯器必須已經知道所有用RTTI來處理的類型。但是,當你從網絡連接中獲得一串字節,並被告知這些字節代表一個類。可是編譯器並不知道這個類的信息。這時你要使用這個類,那麼就得使用反射機制

12、RTTI與反射之間的區別:對RTTI來書,編譯器在編譯時打開和檢查.class文件,而對於反射機制,.class文件在編譯時是不可獲取的,所以是在運行時打開和檢查.class文件的。

13、獲取關於類和對象的反射信息在java.lang.reflect庫中,它包含了Field、Method以及Constructor類。

1).Field 提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)字段或實例字段。

2). Method 提供關於類或接口上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。

3). Constructor 提供關於類的單個構造方法的信息以及對它的訪問權限。 

Base類如下:

class Base{
	private int number = 1;
	public int otherNum = 100;
	public Base(){
		
	}
	public Base(int number){
		this.number = number;
	}
	public void func(){
		number++;
	}
	public void otherFunc(){
		otherNum--;
	}
}
Test:

public class Test{
	public static void main(String[] args){
		Constructor[] constructors = null;
		Method[] methods = null;
		Field[] fields = null;
		try {
			Class c = Class.forName("Base");
			constructors = c.getConstructors();//公有構造方法。
			methods = c.getMethods();//公有方法。
			fields = c.getFields();//公有字段。
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		System.out.println("Base含有的公有構造方法:");
		for(int i = 0; i < constructors.length; i++){
			System.out.println(constructors[i].getName());
		}
		System.out.println("Base含有的公有方法(有些是從Oject繼承的):");
		for(int i = 0; i < methods.length; i++){
			System.out.println(methods[i].getName());	
		}
		System.out.println("Base含有的公有字段:");
		for(int i = 0; i < fields.length; i++){
			System.out.println(fields[i].getName());		
		}
	}
}
運行結果:


發佈了62 篇原創文章 · 獲贊 29 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章