java語言

當前位置 /首頁/計算機/java語言/列表

Java反射機制應用實踐

引導語:通過反射機制我們可以在執行期間獲取物件的型別資訊,利用這一特性我們可以實現工廠模式和代理模式等設計模式,以下是小編整理的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));

}

}

TAG標籤:機制 實踐 JAVA #