在實(shí)踐中了解Java反射機(jī)制應(yīng)用

引言

公司主營(yíng)業(yè)務(wù):網(wǎng)站建設(shè)、成都網(wǎng)站制作、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出德陽(yáng)免費(fèi)做網(wǎng)站回饋大家。

Java反射機(jī)制是一個(gè)非常強(qiáng)大的功能,在很多大型項(xiàng)目比如Spring, Mybatis都可以看見反射的身影。通過反射機(jī)制我們可以在運(yùn)行期間獲取對(duì)象的類型信息,利用這一特性我們可以實(shí)現(xiàn)工廠模式和代理模式等設(shè)計(jì)模式,同時(shí)也可以解決Java泛型擦除等令人苦惱的問題。本文我們就從實(shí)際應(yīng)用的角度出發(fā),來應(yīng)用一下Java的反射機(jī)制。

反射基礎(chǔ)

p.s: 本文需要讀者對(duì)反射機(jī)制的API有一定程度的了解,如果之前沒有接觸過的話,建議先看一下官方文檔的Quick Start。

在應(yīng)用反射機(jī)制之前,首先我們先來看一下如何獲取一個(gè)對(duì)象對(duì)應(yīng)的反射類Class,在Java中我們有三種方法可以獲取一個(gè)對(duì)象的反射類。

通過getClass方法

在Java中,每一個(gè)Object都有一個(gè)getClass方法,通過getClass方法我們可以獲取到這個(gè)對(duì)象對(duì)應(yīng)的反射類:

String s = "ziwenxie";
Class<?> c = s.getClass();

通過forName方法

我們也可以調(diào)用Class類的靜態(tài)方法forName:

Class<?> c = Class.forName("java.lang.String");

使用.class

或者我們也可以直接使用.class:

Class<?> c = String.class;

獲取類型信息

在文章開頭我們就提到反射的一大好處就是可以允許我們?cè)谶\(yùn)行期間獲取對(duì)象的類型信息,下面我們通過一個(gè)例子來具體看一下。

首先我們?cè)趖ypeinfo.interfacea包下面新建一個(gè)接口A:

package typeinfo.interfacea;
public interface A { void f(); }

接著我們?cè)趖ypeinfo.packageaccess包下面新建一個(gè)接口C,接口C繼承自接口A,并且我們還另外創(chuàng)建了幾個(gè)用于測(cè)試的方法,注意下面幾個(gè)方法的權(quán)限都是不同的。

package typeinfo.packageaccess;
import typeinfo.interfacea.A;
class C implements A {
public void f() { System.out.println("public C.f()"); }
public void g() { System.out.println("public C.g()"); }
protected void v () { System.out.println("protected C.v()"); }
void u() { System.out.println("package C.u()"); }
private void w() { System.out.println("private C.w()"); }
}
public class HiddenC {
public static A makeA() { return new C(); }
}

在callHiddenMethod()方法中我們用到了幾個(gè)新的API,其中g(shù)etDeclaredMethod()根據(jù)方法名用于獲取Class類指代對(duì)象的某個(gè)方法,然后我們通過調(diào)用invoke()方法傳入實(shí)際的對(duì)象就可以觸發(fā)對(duì)象的相關(guān)方法:

package typeinfo;
import typeinfo.interfacea.A;
import typeinfo.packageaccess.HiddenC;
import java.lang.reflect.Method;
public class HiddenImplementation {
public static void main(String[] args) throws Exception {
A a = HiddenC.makeA();
a.f();
System.out.println(a.getClass().getName());
// 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 = a.getClass().getDeclaredMethod(methodName);
g.setAccessible(true);
g.invoke(a);
}
}


從輸出結(jié)果我們可以看出來,不管是public,default,protect還是pricate方法,通過反射類我們都可以自由調(diào)用。當(dāng)然這里我們只是為了顯示反射的強(qiáng)大威力,在實(shí)際開發(fā)中這種技巧還是不提倡。

public C.f()
typeinfo.packageaccess.C
public C.g()
package C.u()
protected C.v()
private C.w()

應(yīng)用實(shí)踐

我們有下面這樣一個(gè)業(yè)務(wù)場(chǎng)景,我們有一個(gè)泛型集合類List<Class<? extends Pet>>,我們需要統(tǒng)計(jì)出這個(gè)集合類中每種具體的Pet有多少個(gè)。由于Java的泛型擦除,注意類似List<? extends Pet>的做法肯定是不行的,因?yàn)榫幾g器做了靜態(tài)類型檢查之后,到了運(yùn)行期間JVM會(huì)將集合中的對(duì)象都視為Pet,但是并不會(huì)知道Pet代表的究竟是Cat還是Dog,所以到了運(yùn)行期間對(duì)象的類型信息其實(shí)全部丟失了。p.s: 關(guān)于泛型擦除:我在上一篇文章里面有詳細(xì)解釋,感興趣的朋友可以看一看。

為了實(shí)現(xiàn)我們上面的例子,我們先來定義幾個(gè)類:

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類的的實(shí)現(xiàn)稍微復(fù)雜一點(diǎn),我們實(shí)現(xiàn)了Comparable接口,重新自定義了類的比較規(guī)則,如果不是很明白的話,也沒有關(guān)系,我們已經(jīng)將它抽象出來了,所以不理解實(shí)現(xiàn)原理也沒有關(guān)系。

public class Individual implements Comparable<Individual> {
private static long counter = 0;
private final long id = counter++;
private String name; // name is optional
public Individual(String name) { this.name = name; }
public Individual() {}
public String toString() {
return getClass().getSimpleName() + (name == null ? "" : " " + name);
}
public long id() { return id; }
public boolean equals(Object o) {
return o instanceof Individual && id == ((Individual)o).id;
}
public int hashCode() {
int result = 17;
if (name != null) {
result = 37 * result + name.hashCode();
}
result = 37 * result + (int) id;
return result;
}
public int compareTo(Individual arg) {
// Compare by class name first:
String first = getClass().getSimpleName();
String argFirst = arg.getClass().getSimpleName();
int firstCompare = first.compareTo(argFirst);
if (firstCompare != 0) {
return firstCompare;
}
if (name != null && arg.name != null) {
int secendCompare = name.compareTo(arg.name);
if (secendCompare != 0) {
return secendCompare;
}
}
return (arg.id < id ? -1 : (arg.id == id ? 0 : 1));
}
}


下面創(chuàng)建了一個(gè)抽象類PetCreator,以后我們通過調(diào)用arrayList()方法便可以直接獲取相關(guān)Pet類的集合。這里使用到了我們上面沒有提及的newInstance()方法,它會(huì)返回Class類所真正指代的類的實(shí)例,這是什么意思呢?比如說聲明new Dog().getClass().newInstance()和直接new Dog()是等價(jià)的。

public abstract class PetCreator {
private Random rand = new Random(47);
// The List of the different getTypes of Pet to create:
public abstract List<Class<? extends Pet>> getTypes();
public Pet randomPet() {
// Create one random Pet
int n = rand.nextInt(getTypes().size());
try {
return getTypes().get(n).newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public Pet[] createArray(int size) {
Pet[] result = new Pet[size];
for (int i = 0; i < size; i++) {
result[i] = randomPet();
}
return result;
}
public ArrayList<Pet> arrayList(int size) {
ArrayList<Pet> result = new ArrayList<Pet>();
Collections.addAll(result, createArray(size));
return result;
}
}

接下來我們來實(shí)現(xiàn)上面這一個(gè)抽象類,解釋一下下面的代碼,在下面的代碼中,我們聲明了兩個(gè)集合類,allTypes和types,其中allTypes中包含了我們呢上面所聲明的所有類,但是我們具體的類型實(shí)際上只有兩種即Mutt和EgypianMau,所以我們真正需要new出來的寵物只是types中所包含的類型,以后我們通過調(diào)用getTypes()便可以得到types中所包含的所喲類型。

public class LiteralPetCreator extends PetCreator {
@SuppressWarnings("unchecked")
public static final List<Class<? extends Pet>> allTypes = Collections.unmodifiableList(
Arrays.asList(Pet.class, Dog.class, Cat.class, Mutt.class, EgyptianMau.class));
private static final List<Class<? extends Pet>> types = allTypes.subList(
allTypes.indexOf(Mutt.class), allTypes.size());
public List<Class<? extends Pet>> getTypes() {
return types;
}
}


總體的邏輯已經(jīng)完成了,最后我們實(shí)現(xiàn)用來統(tǒng)計(jì)集合中相關(guān)Pet類個(gè)數(shù)的TypeCounter類。解釋一下isAssignalbeFrom()方法,它可以判斷一個(gè)反射類是某個(gè)反射類的子類或者間接子類。而getSuperclass()顧名思義就是得到某個(gè)反射類的父類了。

public class TypeCounter extends HashMap<Class<?>, Integer> {
private Class<?> baseType;
public TypeCounter(Class<?> baseType) {
this.baseType = baseType;
}
public void count(Object obj) {
Class<?> type = obj.getClass();
if (!baseType.isAssignableFrom(type)) {
throw new RuntimeException(
obj + " incorrect type " + type + ", should be type or subtype of " + baseType);
}
countClass(type);
}
private void countClass(Class<?> type) {
Integer quantity = get(type);
put(type, quantity == null ? 1 : quantity + 1);
Class<?> superClass = type.getSuperclass();
if (superClass != null && baseType.isAssignableFrom(superClass)) {
countClass(superClass);
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder("{");
for (Map.Entry<Class<?>, Integer> pair : entrySet()) {
result.append(pair.getKey().getSimpleName());
result.append("=");
result.append(pair.getValue());
result.append(", ");
}
result.delete(result.length() - 2, result.length());
result.append("} ");
return result.toString();
}
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

網(wǎng)頁(yè)名稱:在實(shí)踐中了解Java反射機(jī)制應(yīng)用
轉(zhuǎn)載源于:http://muchs.cn/article2/gddioc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、軟件開發(fā)、網(wǎng)站改版、小程序開發(fā)、網(wǎng)站策劃、企業(yè)網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)