Java反射

Class
  簡介
  總結1
  獲取Class實例
  獲取class信息
  判斷class類型
  創建class實例
  總結
訪問字段
  field
  Field對象
  SecurityManager
  總結
調用方法
  method
  Method對象
  SecurityManager
  多態
  總結
調用構造方法
  newInstance
  Constructor對象
  SecurityManager
  總結
獲取繼承關係
  getSuperclass()
  getInterfaces()
  isAssignableFrom()
  總結

Class

簡介

class / interface的數據類型都是Class,每加載一個class,JVM就爲其創建一個Class類型的實例,並關聯起來
在這裏插入圖片描述

JVM持有的每個Class實例都指向一個數據類型(class 或 interface)
在這裏插入圖片描述
一個Class實例包含了該class的完整信息
在這裏插入圖片描述

總結1
  • JVM爲每個加載的class創建對應的Class實例,並在實例中保存該class的所有信息
  • 如果獲取了某個Class實例,則可以獲取到該實例對應的class的所有信息
  • 通過Class實例獲取class信息的方法稱爲反射(Reflection)
獲取Class實例
  • Type.class
Class cls = String.class;
  • getClass()
String s = "name";
Class cls = s.getClass();
  • Class.forName()
Class cls = Class.forName("java.lang.String");
獲取class信息
  • getName()
Class cls = String.class;
Stirng fname = cls.getName(); // "java.lang.String"
  • getSimpleName()
String sname = cls.getSimpleName(); // "String"
  • getPackage()
String pkg = cls.getPackage().getName(); // "java.lang"
判斷class類型
  • isInterface() 是否是接口
Runnable.class.isInterface();// true
  • isEnum() 是否是枚舉
java.time.Month.class.isEnum(); // true
  • isArray() 是否是數組
String[].class.isArray();	// true
  • isPrimitive() 是否是基本類型
int.class.isPrimitive();	// true
創建class實例
  • newInstance()
Class cls = String.class;
String s = (String)cls.newInstance();	// new String()
總結
  • JVM爲每個加載的class創建對應的Class實例來保存class的所有信息
  • 獲取一個class對應的Class實例後,就可以獲取該class的所有信息
  • 通過Class實例獲取class信息的方法稱爲反射(Reflection)
  • JVM總是動態加載class,可以在運行期根據條件控制加載class

訪問字段

field

通過Class實例獲取field信息:

  • getField(name) 獲取某個public的field(包括父類)
  • getDeclaredField(name) 獲取當前類的某個field(不包括父類)
  • getFields() 獲取所有的public的field(包括父類)
  • getDeclaredFields() 獲取當前類的所有field(不包括父類)
Field對象

Field對象包含一個field的所有信息

  • getName() 名稱
  • getType() 類型
  • getModifiers() 修飾符
  • get(Object) 獲取一個實例的該字段的值
  • set(Object, Object) 設置一個實例的該字段的值
SecurityManager

setAccessible(true)可以允許訪問非public字段,但是可能會失敗:

  • 定義了SecurityManager
  • SecurityManager的規則組織對該Field設置accessible:例如,規則應用於所有java和javax開頭的package的類
總結
  • Field對象封裝了字段的所有信息
  • 通過Class實例的方法可以獲取Field實例:getField / getFields / getDeclaredField / getDeclaredFields
  • 通過Field實例可以獲取字段信息:getName / getType / getModifiers
  • 通過Field實例可以讀取或設置某個對象的字段:get(Object instance) / set(Object instance, Object fieldValue)
  • 通過設置setAccessible(true)來訪問非public字段

調用方法

method

通過Class實例獲取method信息

  • getMethod(name, Class…):獲取某個public的method(包括父類)
  • getDeclaredMethod(name, Class…):獲取當前類的某個method(不包括父類)
  • getMethods():獲取所有public的method(包括父類)
  • getDeclaredMethods():獲取當前類的所有method(不包括父類)
Method對象

Method對象包含一個method的所有信息

  • getName() 方法名稱
  • getReturnType()
  • getParameterType()
  • getModifiers()

方法調用

  • 調用無參數的Method :Object invoke(Object obj)
Integer n = new Integer(123);
Class cls = n.getClass();
Method m = cls.getMethod("toString");
String s = (String)m.invoke(n); 
// 相當於 String s = n.toString()
  • 調用帶參數的Method :Object invoke(Object obj, Object…args)
Integer n = new Integer(123);
Class cls = n.getClass();
Method m = cls.getMethod("compareTo", Integer.class);
int r = (Integer)m.invoke(n, 456); 
// 相當於 int r = n.compareTo(456)
SecurityManager

setAccessible(true)可以允許訪問非public方法,但是可能會失敗:

  • 定義了SecurityManager
  • SecurityManager的規則組織對該Method設置accessible:例如,規則應用於所有java和javax開頭的package的類
多態

從父類的Class實例獲取的Method,作用於子類實例時:

  • 實際調用方法是子類覆寫的方法
  • 保證了多態的正確性
class Person {
  	public void hello() {
      	System.out.println("Person:hello");
    }
}
class Student extends Person {
  	public void hello() {
      	System.out.println("Student:hello");
    }
}
Method m = Person.class.getMethod("hello");
m.invoke(new Student());
// Student:hello
總結
  • Method對象封裝了方法的所有信息
  • 通過Class實例的方法可以獲取Method實例:getMethod / getMethods / getDeclaredMethod / getDeclaredMethods
  • 通過Method實例可以獲取方法信息:getName / getReturnType / getParameterTypes / getModifiers
  • 通過Method實例可以調用某個對象的方法:Object invoke(Object instance, Object…parameters)
  • 通過設置setAccessible(true)來訪問非public方法

調用構造方法

newInstance

Class.newInstance()只能調用public無參構造方法

Constructor對象

Constructor對象包含一個構造方法的所有信息,可以創建一個實例:

Class cls = Integer.class;
// Integer(int)
Constructor cons1 = cls.getConstructor(int.class);
Integer n1 = (Integer)cons1.newInstance(123);
//Integer(String)
Constructor cons2 = cls.getConstructor(String.class);
Integer n1 = (Integer)cons1.newInstance("123");

通過Class實例獲取Constructor信息:(都是本類的,和父類無關)

  • getConstructor(Class…):獲取某個public的Constructor
  • getDeclaredConstructor(Class…):獲取某個Constructor
  • getConstructors():獲取所有public的Constructor
  • getDeclaredConstructors():獲取所有Constructor
SecurityManager

setAccessible(true)可以允許訪問非public構造方法,但是可能會失敗:

  • 定義了SecurityManager
  • SecurityManager的規則組織對該Constructor設置accessible:例如,規則應用於所有java和javax開頭的package的類
總結
  • Constructor對象封裝了構造方法的所有信息
  • 通過Class實例的方法可以獲取Constructor實例:getConstructor / getConstructors / getDeclaredConstructor / getDeclaredConstructors
  • 通過Constructor實例可以創建一個實例對象:newInstance(Object…parameters)
  • 通過設置setAccessible(true)來訪問非public構造方法

獲取繼承關係

getSuperclass()

獲取父類的Class:

  • Class getSuperclass()
  • Object的父類是null
  • interface的父類是null
getInterfaces()

獲取當前類直接實現的interface:

  • Class[] getInterfaces()
  • 不包括間接實現的interface
  • 沒有interface的class返回空數組
  • interface返回繼承的interface
isAssignableFrom()

判斷一個向上轉型是否成立:

  • bool isAssignableFrom()
// Integer i= 1;
// Number x = i是否成立
Number.class.isAssignableFrom(Integer.class); // true
總結
  • 通過Class對象可以獲取繼承關係:
    • getSuperclass()
    • getInterfaces()
  • 通過Class對象的isAssignableFrom()方法可以判斷一個向上轉型是否正確
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章