JAVA 反射
來源:程序員人生 發布時間:2015-05-27 08:17:10 閱讀次數:2417次
每一個類都會有1個Class對象,所有的類都是在首次使用時動態加載到JVM中。類加載器首先會檢查該類的Class對象是不是已被加載,如果還沒有被夾在。默許的類加載器就會根據類名查找.class文件,然后加載該類到內存。他就用來創建這個類的所有對象。
1. Class對象:
1.1 獲得1個類的Class對象: Class.forName();或使用類字面常量,這樣做在編譯期會接受檢查,不需要捕獲異常。不但普通的類,接口、數組及基本數據類型都有字面常量。類名.class
1.2 Class類。Class對象總是指向某個Class對象,可以制造類的實例,包括該類的靜態成員,作用于這些事例的所有方法代碼。JAVA 1.5之前使用的是普通類援用,1.5以后將類援用使用泛型語法變得更加具體。使用泛型語法的類以后,會讓編譯器強迫履行額外的類型檢查。為了使用泛化的Class援用時放松限制,可使用通配符“?”,表示任何事物。使用普通的Class援用時若果出錯,直到運行的時候才會被發現。創建Class援用,被限定為某種類型或該類型的任何子類型,可使用<?
extends >
注:Class<?>和Class是等價的,Class<?>的好處是表示程序員就是自己選擇使用非具體的版本而不是由于忽視。
public class TestReflection {
public static void main(String[] args) {
Class intClass1 = int.class;
Class doubleClass1 = double.class;
Class<Integer> intClass2 = int.class;// Class<Integer> intClass2 = Integer.class;
Class<Double> doubleClass2 = double.class;
// intClass2 = double.class; // error
Class<?> intClass3 = int.class;
Class<? extends Number> int_double_class;
int_double_class = int.class;
int_double_class = double.class;
}
}
1.3 普通的Class和泛化的Class還有個區分,在使用泛型語法的Class時使用newInstance()返回該對象的確切類型,而普通的Class返回的是Object
class A{
public void print(){
System.out.println("AAA");
}
}
public class TestReflection {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class aClass1 = A.class;
Object obj = aClass1.newInstance();
((A)obj).print();
Class<A> aClass2 = A.class;
A a2 = aClass2.newInstance();
a2.print();
}
}
1.4 使用泛型語法取得父類的Class援用
class A{}
class B extends A{}
public class TestReflection {
public static void main(String[] args) throws InstantiationException, IllegalAccessException{
Class<B> bClass = B.class;
Class<? super B> aClass1 = bClass.getSuperclass();
// 不能寫成下面的情勢,雖然在編譯的時候在編譯起見就知道B的父類是A
// Class<A> aClass2 = bClass.getSuperclass(); // error
// 正由于上面的到的 aClass1 的含糊性,下面得到的返回值也不是精確類型而是Object
Object aClassObj = aClass1.newInstance();
}
}
2. 反射相干類 : java.lang.reflect包 包括了Field、Method、Constructor類,每一個類都實現了Menber接口。這些類對象都是在JVM運行時創建的。
反射機制提供了足夠的支持,使得能夠創建1個在編譯時完全未知的對象,并調用此對象的方法。
2.1 獲得類的構造函數、屬性和方法
class A{
private int i;
public A (int x) {
i = x;
}
public void print() {
System.out.println("AAA");
}
}
public class TestReflection {
public static void main(String[] args) throws InstantiationException, IllegalAccessException{
Class<?> aClass = null;
try {
aClass = Class.forName("reflection.A");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("------------類所有方法------------");
Method [] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.toString());
}
System.out.println("------------類構造方法------------");
Constructor [] constructors = aClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.toString());
}
System.out.println("------------類屬性------------");
// Field [] fields = aClass.getFields();//獲得public的
Field [] fields = aClass.getDeclaredFields(); //獲得public的
for (Field field : fields) {
System.out.println(field.toString());
}
}
}
//getFields()與getDeclaredFields()區分:
//getFields()只能訪問類中聲明為公有的字段,getDeclaredFields()能訪問類中所有的字段
//getMethods()與getDeclaredMethods()區分:
//getMethods()只能訪問類中聲明為公有的方法,能訪問從其它類繼承來的公有方法,getDeclaredFields()能訪問類中所有的字段,不能訪問從其它類繼承來的方法
//getConstructors()只能訪問類中聲明為public的構造函數,getDeclaredConstructors()能訪問類中所有的構造函數
2.2 創建對象
class A{
private int i;
public A(){}
private A (int x) {
i = x;
}
public void print() {
System.out.println("AAA");
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
public class TestReflection {
public static void main(String[] args){
try {
Class<A> aClass = A.class;
//創建對象的兩種方式
// 1. Class.newInstance
aClass.newInstance();// 必須有默許的構造函數
// 2. Constructor.newInstance
Constructor<A> intConstructors = aClass.getDeclaredConstructor(int.class); // new Class<?> []{int.class}
intConstructors.setAccessible(true);
A a = intConstructors.newInstance(100);
System.out.println(a.getI());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.3 訪問類屬性 1般用來修改源碼中類成員的值
<pre name="code" class="java">class A{
private static boolean isOpen = false;
public static boolean isOpen() {
return isOpen;
}
}
public class TestReflection {
public static void main(String[] args){
try {
System.out.println(A.isOpen());
Field openField = A.class.getDeclaredField("isOpen");
openField.setAccessible(true);
openField.setBoolean(new A(), true);
System.out.println(A.isOpen());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.4 調用函數
<pre name="code" class="java">class A{
private void print() {
System.out.println("AAA");
}
}
public class TestReflection {
public static void main(String[] args){
try {
A a = new A();
Class<A> aClass = (Class<A>) a.getClass();
aClass.getDeclaredMethod("print");
Method printMethod = aClass.getDeclaredMethod("print");//Method printMethod = aClass.getDeclaredMethod("print", new Class<?>[]{});
printMethod.setAccessible(true);
printMethod.invoke(a);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注:利用反射調用私有屬性、構造函數或方法時要設置Accessible屬性為true。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈