反射
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
1)關於機制
Reflection 是Java被視爲動態關鍵性質。這個機制允許程序在APIs取得任何一個已知名稱的cmodifiers(諸如public, stati例如Object)、實現之interfa,也包括fields和methods的所變fields內容或調用methods
2)Java 反射機制主要提供了以下功能:
• 在運行時判斷任意一個對象所屬的類。
• 在運行時構造任意一個類的對象。
• 在運行時判斷任意一個類所具有的成員變量和方法。
• 在運行時調用任意一個對象的方法
Java反射機制實現
主要由以下類來實現Java反射機制,這些類都位於java.lang.reflect包中
– Class類:代表一個類。
– Field 類:代表類的成員變量(成員變量也稱爲類的屬性)。
– Method類:代表類的方法。
– Constructor 類:代表類的構造方法。
– Array類:提供了動態創建數組,以及訪問數組的元素的靜態方法
2)獲取class的三種方式
a) 使用Class類的靜態方法forName:Class.forName(“java.lang.String”);
Class<?> classType = Class.forName(“java.lang.Object”);
Method[] methods = classType.getDeclaredMethods();
b) 使用類的.class 語法:String.class;
Class<?> classType = InvokeTester.class;
Object invokeTester = classType.newInstance();
Method addMethod = classType.getMethod("add", new Class[] { int.class,
int.class });
Object result = addMethod.invoke(invokeTester, new Object[]{1, 2});
c) 使用對象的getClass()方法:
classType = (Class<Fruit>) e.getClass();
3)若想通過類的不帶參數的構造方法來生成對象,我們有兩種方式
a) 先獲得Class對象,然後通過該Class對象的newInstance()方法直接生成即可
Class<?> classType = String.class;
Object obj = classType.newInstance();
b) 先獲得Class對象,然後通過該對象獲得對應的Constructor對象,再通過該Constructor對象的newInstance()方法生成:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});
c)若想通過類的帶參數的構造方法生成對象,只能使用下面這一種方式:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{String.class, int.class});
Object obj = cons.newInstance(new Object[]{“hello”, 3});
4)對象數組
Class<?> classType = Class.forName("java.lang.String");
Array.set(array, 5, "hello");
String str = (String)Array.get(array, 5);//hello
5)多維數組
int[] dims = new int[] { 5, 10, 15 };
Object array = Array.newInstance(Integer.TYPE, dims);
Object arrayObj = Array.get(array, 3);
arrayObj = Array.get(arrayObj, 5);
Array.setInt(arrayObj, 10, 37);
int[][][] arrayCast = (int[][][]) array;
6)訪問私有
Private p = new Private();
Class<?> classType = p.getClass();
Field field = classType.getDeclaredField("name");//獲取屬性
field.setAccessible(true);//壓制Java對訪問修飾符的檢查
field.set(p, "lisi");
Private p = new Private();
Class<?> classType = p.getClass();
//獲取屬性
Method method=classType.getDeclaredMethod("hello",new Class[] { String.class });
method.setAccessible(true);//壓制Java的訪問控制檢查
String str = (String)method.invoke(p, new Object[]{"zhangsan"});
public class TestReflection {
public static void main(String[] args) throws Exception {
Class<?> classType = null;
//獲取類方式一
classType = Class.forName("com.Fruit");
//獲取類方式二
classType = Fruit.class;
//獲取類方式三
Fruit e = new Fruit();
classType = (Class<Fruit>) e.getClass();
//實例方式一
Object invokeTester = classType.newInstance();
//實例方式二 利用構造
Constructor cons = classType.getConstructor(new Class[]{});
invokeTester = cons.newInstance(new Object[]{});
//方式三 利用帶參構造
cons = classType.getConstructor(new Class[]{String.class, String.class});
invokeTester = cons.newInstance(new Object[]{"apple", "red"});
Method addMethod = classType.getMethod("add", new Class[] { int.class,
int.class });
Object result = addMethod.invoke(invokeTester, new Object[] { 1, 2 });
System.out.println(result.toString());//3
//對象數組
classType = Class.forName("java.lang.String");
Object array = Array.newInstance(classType, 10);
Array.set(array, 5, "hello");
String str = (String)Array.get(array, 5);
System.out.println(str);//hello
//多維數組
int[] dims = new int[] { 5, 10, 15 };
Object arrayOut = Array.newInstance(Integer.TYPE, dims);
Object arrayObj = Array.get(arrayOut, 3);
arrayObj = Array.get(arrayObj, 5);
Array.setInt(arrayObj, 10, 37);
int[][][] arrayCast = (int[][][]) arrayOut;
//訪問私有方法
classType = Fruit.class;
Fruit fruit = new Fruit();
Field field = classType.getDeclaredField("price");
field.setAccessible(true);//壓制Java對訪問修飾符的檢查
field.set(fruit, 5);
System.out.println(fruit.getPrice());//5
Method method=classType.getDeclaredMethod("sell",new Class[] { String.class });
method.setAccessible(true);//壓制Java的訪問控制檢查
String methodstr = (String)method.invoke(fruit, new Object[]{"suning"});//sell
}
}
反射與框架
比如讀取配置文件的字符串生成實體(如果是配置則結合註解讀取)
JUnit4的執行的一般流程:
a) 首先獲得待測試類所對應的Class對象。
b) 然後通過該Class對象獲得當前類中所有public方法所對應的Method數組。
c) 遍歷該Method數組,取得每一個Method對象
d) 調用每個Method對象的isAnnotationPresent(Test.class)方法,判斷該方法是否被Test註解所修飾。
e) 如果該方法返回true,那麼調用method.invoke()方法去執行該方法,否則不執行。
反射機制和註解的綜合使用
public class Goal {
@MyAnnotation(hello = "aaa", world = "bbb")
@Deprecated
@SuppressWarnings("unchecked")
public void output() {
System.out.println("output something!");
}
}
註解類:import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{
String hello() default "hello u";
String world();
}
測試:
public class Test {
public static void main(String[] args) throws Exception {
//反射類
Class<?> classType = Goal.class;
Object myTest = classType.newInstance();
Method method = classType.getDeclaredMethod("output", new Class[]{});
//註解處理
if(method.isAnnotationPresent(MyAnnotation.class)) {
method.invoke(myTest, new Object[]{});
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String hello = myAnnotation.hello();
String world = myAnnotation.world();
System.out.println(hello + ", " + world);
}
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation.annotationType().getName());
}
}
}