Java反射機制應用實踐
引導語:通過反射機制我們可以在運行期間獲取對象的類型信息,利用這一特性我們可以實現工廠模式和代理模式等設計模式,以下是小編整理的Java反射機制應用實踐,歡迎參考閲讀!
反射基礎
p.s: 本文需要讀者對反射機制的API有一定程度的瞭解,如果之前沒有接觸過的話,建議先看一下官方文檔的Quick Start。
在應用反射機制之前,首先我們先來看一下如何獲取一個對象對應的反射類Class,在Java中我們有三種方法可以獲取一個對象的反射類。
通過getClass方法
在Java中,每一個Object都有一個getClass方法,通過getClass方法我們可以獲取到這個對象對應的反射類:
String s = "ziwenxie";
Class c = lass();
通過forName方法
我們也可以調用Class類的靜態方法forName:
Class c = ame("ng");
使用s
或者我們也可以直接使用s:
Class c = s;
獲取類型信息
在文章開頭我們就提到反射的一大好處就是可以允許我們在運行期間獲取對象的類型信息,下面我們通過一個例子來具體看一下。
首先我們在rfacea包下面新建一個接口A:
package rfacea;
public interface A { void f(); }
接着我們在ageaccess包下面新建一個接口C,接口C繼承自接口A,並且我們還另外創建了幾個用於測試的方法,注意下面幾個方法的權限都是不同的。
package ageaccess;
import rfacea.A;
class C implements A {
public void f() { tln("public C.f()"); }
public void g() { tln("public C.g()"); }
protected void v () { tln("protected C.v()"); }
void u() { tln("package C.u()"); }
private void w() { tln("private C.w()"); }
}
public class HiddenC {
public static A makeA() { return new C(); }
}
在callHiddenMethod()方法中我們用到了幾個新的API,其中getDeclaredMethod()根據方法名用於獲取Class類指代對象的某個方法,然後我們通過調用invoke()方法傳入實際的對象就可以觸發對象的相關方法:
package typeinfo;
import rfacea.A;
import enC;
import od;
public class HiddenImplementation {
public static void main(String[] args) throws Exception {
A a = A();
a.f();
tln(lass()ame());
// Oops! Reflection still allows us to call g():
callHiddenMethod(a, "g");
// And even methods that are less accessible!
callHiddenMethod(a, "u");
callHiddenMethod(a, "v");
callHiddenMethod(a, "w");
}
static void callHiddenMethod(Object a, String methodName) throws Exception {
Method g = lass()eclaredMethod(methodName);
ccessible(true);
ke(a);
}
}
從輸出結果我們可以看出來,不管是public,default,protect還是pricate方法,通過反射類我們都可以自由調用。當然這裏我們只是為了顯示反射的強大威力,在實際開發中這種技巧還是不提倡。
public C.f()
ageaccess.C
public C.g()
package C.u()
protected C.v()
private C.w()
應用實踐
我們有下面這樣一個業務場景,我們有一個泛型集合類List<Class>,我們需要統計出這個集合類中每種具體的Pet有多少個。由於Java的泛型擦除,注意類似List的`做法肯定是不行的,因為編譯器做了靜態類型檢查之後,到了運行期間JVM會將集合中的對象都視為Pet,但是並不會知道Pet代表的究竟是Cat還是Dog,所以到了運行期間對象的類型信息其實全部丟失了。p.s: 關於泛型擦除:我在上一篇文章裏面有詳細解釋,感興趣的朋友可以看一看。
為了實現我們上面的例子,我們先來定義幾個類:
public class Pet extends Individual {
public Pet(String name) { super(name); }
public Pet() { super(); }
}
public class Cat extends Pet {
public Cat(String name) { super(name); }
public Cat() { super(); }
}
public class Dog extends Pet {
public Dog(String name) { super(name); }
public Dog() { super(); }
}
public class EgyptianMau extends Cat {
public EgyptianMau(String name) { super(name); }
public EgyptianMau() { super(); }
}
public class Mutt extends Dog {
public Mutt(String name) { super(name); }
public Mutt() { super(); }
}
上面的Pet類繼承自Individual,Individual類的的實現稍微複雜一點,我們實現了Comparable接口,重新自定義了類的比較規則,如果不是很明白的話,也沒有關係,我們已經將它抽象出來了,所以不理解實現原理也沒有關係。
public class Individual implements Comparable
private static long counter = 0;
private final long id = counter++;
private String name; // name is optional
public Individual(String name) { = name; }
public Individual() {}
public String toString() {
return getClass()impleName() + (name == null ? "" : " " + name);
}
public long id() { return id; }
public boolean equals(Object o) {
return o instanceof Individual && id == ((Individual)o);
}
public int hashCode() {
int result = 17;
if (name != null) {
result = 37 * result + Code();
}
result = 37 * result + (int) id;
return result;
}
public int compareTo(Individual arg) {
// Compare by class name first:
String first = getClass()impleName();
String argFirst = lass()impleName();
int firstCompare = areTo(argFirst);
if (firstCompare != 0) {
return firstCompare;
}
if (name != null && != null) {
int secendCompare = areTo();
if (secendCompare != 0) {
return secendCompare;
}
}
return ( < id ? -1 : ( == id ? 0 : 1));
}
}