1 什么是反射
- Java反射機(jī)制是在運(yùn)行狀態(tài)中
- 對(duì)于任意一個(gè)類扛门,都能知道這個(gè)類的所以屬性和方法;
- 對(duì)于任何一個(gè)對(duì)象,都能夠調(diào)用它的任何一個(gè)方法和屬性炬太;
- 這樣動(dòng)態(tài)獲取新的以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能就叫做反射孔祸。
1 Class類
- Class可以說是反射能夠?qū)崿F(xiàn)的基礎(chǔ)
- class關(guān)鍵字是在聲明java類時(shí)使用的隆敢;而Class 是java JDK提供的一個(gè)類,完整路徑為 java.lang.Class
- 對(duì)于每一種類,Java虛擬機(jī)都會(huì)初始化出一個(gè)Class類型的實(shí)例崔慧,每當(dāng)我們編寫并且編譯一個(gè)新創(chuàng)建的類就會(huì)產(chǎn)生一個(gè)對(duì)應(yīng)Class對(duì)象拂蝎,并且這個(gè)Class對(duì)象會(huì)被保存在同名.class文件里。
- 當(dāng)我們new一個(gè)新對(duì)象或者引用靜態(tài)成員變量時(shí)惶室,Java虛擬機(jī)(JVM)中的類加載器系統(tǒng)會(huì)將對(duì)應(yīng)Class對(duì)象加載到JVM中温自,然后JVM再根據(jù)這個(gè)類型信息相關(guān)的Class對(duì)象創(chuàng)建我們需要實(shí)例對(duì)象或者提供靜態(tài)變量的引用值。
構(gòu)造器是私有的皇钞,只有JVM才可以調(diào)用這個(gè)構(gòu)造函數(shù)創(chuàng)建Class的對(duì)象- 每個(gè)class(注意class是小寫悼泌,代表普通類)類,無論創(chuàng)建多少個(gè)實(shí)例對(duì)象夹界,在JVM中都對(duì)應(yīng)同一個(gè)Class對(duì)象馆里。
- Class是反射能夠?qū)崿F(xiàn)的基礎(chǔ)的另一個(gè)原因是:Java反射包
java.lang.reflect
中的所有類都沒有public構(gòu)造方法,要想獲得這些類實(shí)例,只能通過Class類獲取鸠踪。所以說如果想使用反射丙者,必須得獲得Class對(duì)象。
private Class(ClassLoader loader) {
classLoader = loader;
}
- 通過已有的類得到一個(gè)Class對(duì)象的幾種方式:
1. 通過對(duì)象實(shí)例獲取對(duì)應(yīng)Class對(duì)象Object.getClass()--對(duì)于基本類型無法使用這種方法
//Returns the Class for String
Class c = "foo".getClass();
enum E { A, B }
//Returns the Class corresponding to the enumeration type E.
Class c = A.getClass();
byte[] bytes = new byte[1024];
//Returns the Class corresponding to an array with component type byte.
Class c = bytes.getClass();
Set<String> s = new HashSet<String>();
//Returns the Class corresponding to java.util.HashSet.
Class c = s.getClass();
2.通過類的類型獲取Class對(duì)象,基本類型同樣可以使用這種方法
//The `.class` syntax returns the Class corresponding to the type `boolean`.
Class c = boolean.class;
//Returns the Class for String
Class c = String.class;
3. 通過類的全限定名獲取Class對(duì)象慢哈, 基本類型無法使用此方法
Class c = Class.forName("java.lang.String");//通過Class.forName()方法加載的類蔓钟,采用的是系統(tǒng)類加載器
//對(duì)于數(shù)組比較特殊
Class cDoubleArray = Class.forName("[D"); //相當(dāng)于double[].class
Class cStringArray = Class.forName("[[Ljava.lang.String;"); //相當(dāng)于String[][].class
5.基本類型和void 類型的包裝類可以使用TYPE字段獲取
TYPE Field for Primitive Type Wrappers
Class c = Double.TYPE; //等價(jià)于 double.class.
Class c = Void.TYPE;
6. 另外還有一些反射方法可以獲取Class對(duì)象,但前提是你已經(jīng)獲取了一個(gè)Class對(duì)象卵贱。
Class.getSuperclass()//獲得給定類的父類Class
Class.getClasses()
Class.getDeclaredClasses()
Class.getDeclaringClass()
Class.getEnclosingClass()
java.lang.reflect.Field.getDeclaringClass()
java.lang.reflect.Method.getDeclaringClass()
java.lang.reflect.Constructor.getDeclaringClass()
一般博客都說用這三種
Class c1 = Test.class; //這說明任何一個(gè)類都有一個(gè)隱含的靜態(tài)成員變量class滥沫,這種方式是通過獲取類的靜態(tài)成員變量class得到的()
Class c2 = test.getClass();// test是Test類的一個(gè)對(duì)象,這種方式是通過一個(gè)類的對(duì)象的getClass()方法獲得的 (對(duì)于基本類型無法使用這種方法)
Class c3 = Class.forName("com.catchu.me.reflect.Test"); //這種方法是Class類調(diào)用forName方法键俱,通過一個(gè)類的全量限定名獲得(基本類型無法使用此方法)
例子:通過Class獲取類修飾符和類型
public class TestReflection {
private static final String TAG = "Reflection";
public void testReflection() {
Class<?> c = HashMap.class;
//獲取類名
Log.d(TAG, "Class : " + c.getCanonicalName());
//獲取類限定符
Log.d(TAG, "Modifiers : " + Modifier.toString(c.getModifiers()));
//獲取類泛型信息
TypeVariable[] tv = c.getTypeParameters();
if (tv.length != 0) {
StringBuilder parameter = new StringBuilder("Parameters : ");
for (TypeVariable t : tv) {
parameter.append(t.getName());
parameter.append(" ");
}
Log.d(TAG, parameter.toString());
} else {
Log.d(TAG, " -- No Type Parameters --");
}
//獲取類實(shí)現(xiàn)的所有接口
Type[] intfs = c.getGenericInterfaces();
if (intfs.length != 0) {
StringBuilder interfaces = new StringBuilder("Implemented Interfaces : ");
for (Type intf : intfs){
interfaces.append(intf.toString());
interfaces.append(" ");
}
Log.d(TAG, interfaces.toString());
} else {
Log.d(TAG, " -- No Implemented Interfaces --");
}
//獲取類繼承數(shù)上的所有父類
List<Class> l = new ArrayList<>();
printAncestor(c, l);
if (l.size() != 0) {
StringBuilder inheritance = new StringBuilder("Inheritance Path : ");
for (Class<?> cl : l){
inheritance.append(cl.getCanonicalName());
inheritance.append(" ");
}
Log.d(TAG, inheritance.toString());
} else {
Log.d(TAG, " -- No Super Classes --%n%n");
}
//獲取類的注解(只能獲取到 RUNTIME 類型的注解)
Annotation[] ann = c.getAnnotations();
if (ann.length != 0) {
StringBuilder annotation = new StringBuilder("Annotations : ");
for (Annotation a : ann){
annotation.append(a.toString());
annotation.append(" ");
}
Log.d(TAG, annotation.toString());
} else {
Log.d(TAG, " -- No Annotations --%n%n");
}
}
private static void printAncestor(Class<?> c, List<Class> l) {
Class<?> ancestor = c.getSuperclass();
if (ancestor != null) {
l.add(ancestor);
printAncestor(ancestor, l);
}
}
}
//打印結(jié)果如下
03-29 15:04:23.070 27826-27826/com.example.ming.testproject D/Reflection: Class : java.util.HashMap
03-29 15:04:23.070 27826-27826/com.example.ming.testproject D/Reflection: Modifiers : public
03-29 15:04:23.071 27826-27826/com.example.ming.testproject D/Reflection: Parameters : K V
03-29 15:04:23.071 27826-27826/com.example.ming.testproject D/Reflection: Implemented Interfaces : java.util.Map<K, V> interface java.lang.Cloneable interface java.io.Serializable
03-29 15:04:23.071 27826-27826/com.example.ming.testproject D/Reflection: Inheritance Path : java.util.AbstractMap java.lang.Object
03-29 15:04:23.071 27826-27826/com.example.ming.testproject D/Reflection: -- No Annotations --
2 Member
Reflection defines an interface java.lang.reflect.Member
which is implemented by java.lang.reflect.Field
, java.lang.reflect.Method
, and java.lang.reflect.Constructor
.
類成員主要包括構(gòu)造函數(shù)
兰绣,變量
和方法
,Java中的操作基本都和這三者相關(guān)编振,而Member的這三個(gè)實(shí)現(xiàn)類就分別對(duì)應(yīng)他們缀辩。
java.lang.reflect.Field
:對(duì)應(yīng)類變量
java.lang.reflect.Method
:對(duì)應(yīng)類方法
java.lang.reflect.Constructor
:對(duì)應(yīng)類構(gòu)造函數(shù)
反射就是通過這三個(gè)類才能在運(yùn)行時(shí)改變對(duì)象狀態(tài)。
突破java的權(quán)限檢測(cè)
Java運(yùn)行時(shí)會(huì)進(jìn)行訪問權(quán)限檢查踪央,private類型的變量無法進(jìn)行直接訪問
java.lang.reflect.AccessibleObject
AccessibleObject
為我們提供了一個(gè)方法 setAccessible(boolean flag)臀玄,該方法的作用就是可以取消 Java 語言訪問權(quán)限檢查。所以任何繼承AccessibleObject
的類的對(duì)象都可以使用該方法取消 Java 語言訪問權(quán)限檢查畅蹂。
所以任何繼承AccessibleObject
的類的對(duì)象都可以使用該方法取消 Java 語言訪問權(quán)限檢查健无。(final類型變量也可以通過這種辦法訪問)
public final class Field extends AccessibleObject implements Member
Field
、Method
和Constructor
都是繼承AccessibleObject
2.0 例子
建一個(gè)測(cè)試類
public class Cat {
public static final String TAG = Cat.class.getSimpleName();
private String name;
@Deprecated
public int age;
public Cat(String name, int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void eat(String food){
Log.d(TAG, "eat food " + food);
}
public void eat(String... foods){
StringBuilder s = new StringBuilder();
for(String food : foods){
s.append(food);
s.append(" ");
}
Log.d(TAG, "eat food " + s.toString());
}
public void sleep(){
Log.d(TAG, "sleep");
}
@Override
public String toString() {
return "name = " + name + " age = " + age;
}
}
2.1 Field
通過Field你可以訪問給定對(duì)象的類變量液斜,包括獲取變量的類型累贤、修飾符、注解少漆、變量名臼膏、變量的值或者重新設(shè)置變量值,即使變量是private的示损。
獲取Field
Class提供了4種方法獲得給定類的Field渗磅。
getDeclaredField(String name)
獲取指定的變量(只要是聲明的變量都能獲得,包括private)
getField(String name)
獲取指定的變量(只能獲得public的)
getDeclaredFields()
獲取所有聲明的變量(包括private)
getFields()
獲取所有的public變量
獲取變量類型检访、修飾符夺溢、注解
public void testField(){
Class c = Cat.class;
Field[] fields = c.getDeclaredFields();
for(Field f : fields){
StringBuilder builder = new StringBuilder();
//獲取名稱
builder.append("filed name = ");
builder.append(f.getName());
//獲取類型
builder.append(" type = ");
builder.append(f.getType());
//獲取修飾符
builder.append(" modifiers = ");
builder.append(Modifier.toString(f.getModifiers()));
//獲取注解
Annotation[] ann = f.getAnnotations();
if (ann.length != 0) {
builder.append(" annotations = ");
for (Annotation a : ann){
builder.append(a.toString());
builder.append(" ");
}
} else {
builder.append(" -- No Annotations --");
}
Log.d(TAG, builder.toString());
}
}
打印結(jié)果:
filed name = age type = int modifiers = public annotations = @java.lang.Deprecated()
filed name = name type = class java.lang.String modifiers = private -- No Annotations --
filed name = TAG type = class java.lang.String modifiers = public static final -- No Annotations --
獲取、設(shè)置變量值
通過反射獲取并改變Cat的name和age.
public void testField(){
Cat cat = new Cat("Tom", 2);
Class c = cat.getClass();
try {
//注意獲取private變量時(shí)烛谊,需要用getDeclaredField
Field fieldName = c.getDeclaredField("name");
Field fieldAge = c.getField("age");
fieldName.setAccessible(true);
//反射獲取名字, 年齡
String name = (String) fieldName.get(cat);
int age = fieldAge.getInt(cat);
Log.d(TAG, "before set, Cat name = " + name + " age = " + age);
//反射重新set名字和年齡
fieldName.set(cat, "Timmy");
fieldAge.setInt(cat, 3);
Log.d(TAG, "after set, Cat " + cat.toString());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
2.2 Method
獲取Method
Class依然提供了4種方法獲取Method:
getDeclaredMethod(String name, Class<?>... parameterTypes)
根據(jù)方法名獲得指定的方法风响, 參數(shù)name為方法名,參數(shù)parameterTypes為方法的參數(shù)類型丹禀,如 getDeclaredMethod(“eat”, String.class)
getMethod(String name, Class<?>... parameterTypes)
根據(jù)方法名獲取指定的public方法状勤,其它同上
getDeclaredMethods()
獲取所有聲明的方法
getMethods()
獲取所有的public方法
- 注意:獲取帶參數(shù)方法時(shí)鞋怀,如果參數(shù)類型錯(cuò)誤會(huì)報(bào)NoSuchMethodException,對(duì)于參數(shù)是泛型的情況持搜,泛型須當(dāng)成Object處理(Object.class)
獲取方法返回類型
getReturnType()
獲取目標(biāo)方法返回類型對(duì)應(yīng)的Class對(duì)象
getGenericReturnType()
獲取目標(biāo)方法返回類型對(duì)應(yīng)的Type對(duì)象
這兩個(gè)方法有啥區(qū)別呢密似?
getReturnType()返回類型為Class,getGenericReturnType()返回類型為Type; Class實(shí)現(xiàn)Type葫盼。
返回值為普通簡(jiǎn)單類型如Object, int, String等残腌,getGenericReturnType()返回值和getReturnType()一樣
例如public String function1()
那么各自返回值為:
getReturnType() : class java.lang.String
getGenericReturnType() : class java.lang.String
返回值為泛型
例如public T function2()
那么各自返回值為:
getReturnType() : class java.lang.Object
getGenericReturnType() : T
返回值為參數(shù)化類型
例如public Class<String> function3()
那么各自返回值為:
getReturnType() : class java.lang.Class
getGenericReturnType() : java.lang.Class<java.lang.String>
其實(shí)反射中所有形如getGenericXXX()
的方法規(guī)則都與上面所述類似。
-
獲取方法參數(shù)類型
getParameterTypes()
獲取目標(biāo)方法各參數(shù)類型對(duì)應(yīng)的Class對(duì)象
getGenericParameterTypes()
獲取目標(biāo)方法各參數(shù)類型對(duì)應(yīng)的Type對(duì)象
返回值為數(shù)組贫导,它倆區(qū)別同上 “方法返回類型的區(qū)別” 抛猫。 -
獲取方法聲明拋出的異常的類型
getExceptionTypes()
獲取目標(biāo)方法拋出的異常類型對(duì)應(yīng)的Class對(duì)象
getGenericExceptionTypes()
獲取目標(biāo)方法拋出的異常類型對(duì)應(yīng)的Type對(duì)象
返回值為數(shù)組,區(qū)別同上 -
獲取方法參數(shù)名稱
.class文件中默認(rèn)不存儲(chǔ)方法參數(shù)名稱孩灯,如果想要獲取方法參數(shù)名稱闺金,需要在編譯的時(shí)候加上-parameters
參數(shù)。(構(gòu)造方法的參數(shù)獲取方法同樣)
//這里的m可以是普通方法Method峰档,也可以是構(gòu)造方法Constructor
//獲取方法所有參數(shù)
Parameter[] params = m.getParameters();
for (int i = 0; i < params.length; i++) {
Parameter p = params[i];
p.getType(); //獲取參數(shù)類型
p.getName(); //獲取參數(shù)名稱败匹,如果編譯時(shí)未加上`-parameters`,返回的名稱形如`argX`, X為參數(shù)在方法聲明中的位置讥巡,從0開始
p.getModifiers(); //獲取參數(shù)修飾符
p.isNamePresent(); //.class文件中是否保存參數(shù)名稱, 編譯時(shí)加上`-parameters`返回true,反之flase
}
-
獲取方法修飾符
方法與Filed等類似
method.getModifiers();
- 幾個(gè)Method方法
-
method.isVarArgs()
//判斷方法參數(shù)是否是可變參數(shù)
public Constructor<T> getConstructor(Class<?>... parameterTypes) //返回true
public Constructor<T> getConstructor(Class<?> [] parameterTypes) //返回flase
-
method.isSynthetic()
//判斷是否是復(fù)合方法掀亩,個(gè)人理解復(fù)合方法是編譯期間編譯器生成的方法,并不是源代碼中有的方法 -
method.isBridge()
//判斷是否是橋接方法欢顷,橋接方法是 JDK 1.5 引入泛型后归榕,為了使Java的泛型方法生成的字節(jié)碼和 1.5 版本前的字節(jié)碼相兼容,由編譯器自動(dòng)生成的方法吱涉。可以參考https://www.cnblogs.com/zsg88/p/7588929.html
-
通過反射調(diào)用方法
反射通過Method的invoke()
方法來調(diào)用目標(biāo)方法外里。第一個(gè)參數(shù)為需要調(diào)用的目標(biāo)類對(duì)象怎爵,如果方法為static的,則該參數(shù)為null盅蝗。后面的參數(shù)都為目標(biāo)方法的參數(shù)值鳖链,順序與目標(biāo)方法聲明中的參數(shù)順序一致。
public native Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
- 注意:如果方法是private的墩莫,可以使用method.setAccessible(true)方法繞過權(quán)限檢查
Class<?> c = Cat.class;
try {
//構(gòu)造Cat實(shí)例
Constructor constructor = c.getConstructor(String.class, int.class);
Object cat = constructor.newInstance( "Jack", 3);
//調(diào)用無參方法
Method sleep = c.getDeclaredMethod("sleep");
sleep.invoke(cat);
//調(diào)用定項(xiàng)參數(shù)方法
Method eat = c.getDeclaredMethod("eat", String.class);
eat.invoke(cat, "grass");
//調(diào)用不定項(xiàng)參數(shù)方法
//不定項(xiàng)參數(shù)可以當(dāng)成數(shù)組來處理
Class[] argTypes = new Class[] { String[].class };
Method varargsEat = c.getDeclaredMethod("eat", argTypes);
String[] foods = new String[]{
"grass", "meat"
};
varargsEat.invoke(cat, (Object)foods);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
- 被調(diào)用的方法本身所拋出的異常在反射中都會(huì)以
InvocationTargetException
拋出芙委。換句話說,反射調(diào)用過程中如果異常InvocationTargetException
拋出狂秦,說明反射調(diào)用本身是成功的灌侣,因?yàn)檫@個(gè)異常是目標(biāo)方法本身所拋出的異常。
2.3 Constructor
這節(jié)主要介紹如何通過反射訪問構(gòu)造方法并通過構(gòu)造方法構(gòu)建新的對(duì)象裂问。
獲取構(gòu)造方法
和Method一樣侧啼,Class也為Constructor提供了4種方法獲取
getDeclaredConstructor(Class<?>... parameterTypes)
獲取指定構(gòu)造函數(shù)牛柒,參數(shù)parameterTypes為構(gòu)造方法的參數(shù)類型
getConstructor(Class<?>... parameterTypes)
獲取指定public構(gòu)造函數(shù),參數(shù)parameterTypes為構(gòu)造方法的參數(shù)類型
getDeclaredConstructors()
獲取所有聲明的構(gòu)造方法
getConstructors()
獲取所有的public構(gòu)造方法
構(gòu)造方法的名稱痊乾、限定符皮壁、參數(shù)、聲明的異常等獲取方法都與Method類似哪审,請(qǐng)參照Method
創(chuàng)建對(duì)象
通過反射有兩種方法可以創(chuàng)建對(duì)象:
java.lang.reflect.Constructor.newInstance()
Class.newInstance()
一般來講蛾魄,我們優(yōu)先使用第一種方法;那么這兩種方法有何異同呢湿滓?
-
Class.newInstance()
僅可用來調(diào)用無參的構(gòu)造方法滴须;Constructor.newInstance()
可以調(diào)用任意參數(shù)的構(gòu)造方法 -
Class.newInstance()
會(huì)將構(gòu)造方法中拋出的異常不作處理原樣拋出;Constructor.newInstance()
會(huì)將構(gòu)造方法中拋出的異常都包裝成InvocationTargetException
拋出。 -
Class.newInstance()
需要擁有構(gòu)造方法的訪問權(quán)限;Constructor.newInstance()
可以通過setAccessible(true)
方法繞過訪問權(quán)限訪問private構(gòu)造方法茉稠。
例子在Method一節(jié)已經(jīng)寫過描馅,這里直接截取過來
Class<?> c = Cat.class;
try {
Constructor constructor = c.getConstructor(String.class, int.class);
Cat cat = (Cat) constructor.newInstance( "Jack", 3);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
注意:反射不支持自動(dòng)封箱,傳入?yún)?shù)時(shí)要小心(自動(dòng)封箱是在編譯期間的而线,而反射在運(yùn)行期間)
2.4 數(shù)組和枚舉
數(shù)組和枚舉也是對(duì)象铭污,但是在反射中,對(duì)數(shù)組和枚舉的創(chuàng)建膀篮、訪問和普通對(duì)象有那么一丟丟的不同嘹狞,所以Java反射為數(shù)組和枚舉提供了一些特定的API接口。
2.4.1 數(shù)組
數(shù)組類型
數(shù)組類型:數(shù)組本質(zhì)是一個(gè)對(duì)象誓竿,所以它也有自己的類型磅网。
數(shù)組類型:數(shù)組本質(zhì)是一個(gè)對(duì)象,所以它也有自己的類型筷屡。
例如對(duì)于int[] intArray涧偷,數(shù)組類型為class [I。數(shù)組類型中的[個(gè)數(shù)代表數(shù)組的維度毙死,例如[代表一維數(shù)組燎潮,[[代表二維數(shù)組;[后面的字母代表數(shù)組元素類型扼倘,I代表int确封,一般為類型的首字母大寫(long類型例外,為J)再菊。
class [B //byte類型一維數(shù)組
class [S //short類型一維數(shù)組
class [I //int類型一維數(shù)組
class [C //char類型一維數(shù)組
class [J //long類型一維數(shù)組爪喘,J代表long類型,因?yàn)長(zhǎng)被引用對(duì)象類型占用了
class [F //float類型一維數(shù)組
class [D //double類型一維數(shù)組
class [Lcom.dada.Season //引用類型一維數(shù)組
class [[Ljava.lang.String //引用類型二維數(shù)組
//獲取一個(gè)變量的類型
Class<?> c = field.getType();
//判斷該變量是否為數(shù)組
if (c.isArray()) {
//獲取數(shù)組的元素類型
c.getComponentType()
}
創(chuàng)建和初始化數(shù)組
Java反射為我們提供了java.lang.reflect.Array
類用來創(chuàng)建和初始化數(shù)組纠拔。
//創(chuàng)建數(shù)組秉剑, 參數(shù)componentType為數(shù)組元素的類型,后面不定項(xiàng)參數(shù)的個(gè)數(shù)代表數(shù)組的維度稠诲,參數(shù)值為數(shù)組長(zhǎng)度
Array.newInstance(Class<?> componentType, int... dimensions)
//設(shè)置數(shù)組值秃症,array為數(shù)組對(duì)象候址,index為數(shù)組的下標(biāo),value為需要設(shè)置的值
Array.set(Object array, int index, int value)
//獲取數(shù)組的值种柑,array為數(shù)組對(duì)象岗仑,index為數(shù)組的下標(biāo)
Array.get(Object array, int index)
例子,用反射創(chuàng)建int[] array = new int[]{1, 2}
Object array = Array.newInstance(int.class, 2);
Array.setInt(array , 0, 1);
Array.setInt(array , 1, 2);
注意:反射支持對(duì)數(shù)據(jù)自動(dòng)加寬,但不允許數(shù)據(jù)narrowing(變窄?真難翻譯)聚请。意思是對(duì)于上述set方法荠雕,你可以在int類型數(shù)組中 set short類型數(shù)據(jù),但不可以set long類型數(shù)據(jù)驶赏,否則會(huì)報(bào)IllegalArgumentException炸卑。
-
多維數(shù)組
Java反射沒有提供能夠直接訪問多維數(shù)組元素的API,但你可以把多維數(shù)組當(dāng)成數(shù)組的數(shù)組處理煤傍。
Object matrix = Array.newInstance(int.class, 2, 2);
Object row0 = Array.get(matrix, 0);
Object row1 = Array.get(matrix, 1);
Array.setInt(row0, 0, 1);
Array.setInt(row0, 1, 2);
Array.setInt(row1, 0, 3);
Array.setInt(row1, 1, 4);
或者
Object matrix = Array.newInstance(int.class, 2);
Object row0 = Array.newInstance(int.class, 2);
Object row1 = Array.newInstance(int.class, 2);
Array.setInt(row0, 0, 1);
Array.setInt(row0, 1, 2);
Array.setInt(row1, 0, 3);
Array.setInt(row1, 1, 4);
Array.set(matrix, 0, row0);
Array.set(matrix, 1, row1);
2.4.2 枚舉
枚舉隱式繼承自java.lang.Enum
盖文,Enum繼承自O(shè)bject,所以枚舉本質(zhì)也是一個(gè)類蚯姆,也可以有成員變量五续,構(gòu)造方法,方法等龄恋;對(duì)于普通類所能使用的反射方法疙驾,枚舉都能使用;另外java反射額外提供了幾個(gè)方法為枚舉服務(wù)郭毕。
枚舉隱式繼承自java.lang.Enum
它碎,Enum繼承自O(shè)bject,所以枚舉本質(zhì)也是一個(gè)類显押,也可以有成員變量扳肛,構(gòu)造方法,方法等乘碑;對(duì)于普通類所能使用的反射方法挖息,枚舉都能使用;另外java反射額外提供了幾個(gè)方法為枚舉服務(wù)蝉仇。
Class.isEnum()
Indicates whether this class represents an enum type
Class.getEnumConstants()
Retrieves the list of enum constants defined by the enum in the order they're declared
java.lang.reflect.Field.isEnumConstant()
Indicates whether this field represents an element of an enumerated type
2.5 其它方法
注解中常用的方法:
Annotation[] annotations = (Annotation[]) class1.getAnnotations();//獲取class對(duì)象的所有注解
Annotation annotation = (Annotation) class1.getAnnotation(Deprecated.class);//獲取class對(duì)象指定注解
Type genericSuperclass = class1.getGenericSuperclass();//獲取class對(duì)象的直接超類的
Type Type[] interfaceTypes = class1.getGenericInterfaces();//獲取class對(duì)象的所有接口的type集合
獲取Class對(duì)象其它信息的方法:
boolean isPrimitive = class1.isPrimitive();//判斷是否是基礎(chǔ)類型
boolean isArray = class1.isArray();//判斷是否是集合類
boolean isAnnotation = class1.isAnnotation();//判斷是否是注解類
boolean isInterface = class1.isInterface();//判斷是否是接口類
boolean isEnum = class1.isEnum();//判斷是否是枚舉類
boolean isAnonymousClass = class1.isAnonymousClass();//判斷是否是匿名內(nèi)部類
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);//判斷是否被某個(gè)注解類修飾
String className = class1.getName();//獲取class名字 包含包名路徑
Package aPackage = class1.getPackage();//獲取class的包信息
String simpleName = class1.getSimpleName();//獲取class類名
int modifiers = class1.getModifiers();//獲取class訪問權(quán)限
Class<?>[] declaredClasses = class1.getDeclaredClasses();//內(nèi)部類
Class<?> declaringClass = class1.getDeclaringClass();//外部類
ClassLoader ClassLoader = class1.getClassLoader() 返回類加載器
getSuperclass():獲取某類所有的父類
getInterfaces():獲取某類所有實(shí)現(xiàn)的接口
2.6 靜態(tài)元素
靜態(tài)的類,方法殖蚕,字段和實(shí)例類轿衔,方法,字段完全不一樣睦疫,因?yàn)樗鼰o需初始化類就可以直接使用害驹。
3 反射缺點(diǎn)
- 性能問題。因?yàn)榉瓷涫窃?strong>運(yùn)行時(shí)而不是在編譯時(shí)蛤育,所有不會(huì)利用到編譯優(yōu)化宛官,同時(shí)因?yàn)槭莿?dòng)態(tài)生成葫松,因此,反射操作的效率要比那些非反射操作低得多底洗。
- 安全問題腋么。使用反射技術(shù)要求程序必須在一個(gè)沒有安全限制的環(huán)境中運(yùn)行。如果一個(gè)程序必須在有安全限制的環(huán)境中運(yùn)行亥揖,如Applet珊擂,那么這就是個(gè)問題了。
- 代碼問題费变。由于反射允許代碼執(zhí)行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方法)摧扇,所以使用反射可能會(huì)導(dǎo)致意料之外的副作用--代碼有功能上的錯(cuò)誤,降低可移植性挚歧。反射代碼破壞了抽象性扛稽,因此當(dāng)平臺(tái)發(fā)生改變的時(shí)候,代碼的行為就有可能也隨著變化滑负。
4 動(dòng)態(tài)代理
代理模式(靜態(tài)代理 and 動(dòng)態(tài)代理)
參考
玩轉(zhuǎn) Java 反射
死磕java底層(三)—反射在张、動(dòng)態(tài)代理和注解
Java反射詳解
Java基礎(chǔ)系列—Java反射
Java反射完全解析