欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java反射機(jī)制實(shí)例代碼分享

 更新時(shí)間:2017年11月25日 16:01:39   投稿:mengwei  
這篇文章主要介紹了Java反射機(jī)制實(shí)例代碼分享,具有一定參考價(jià)值,需要的朋友可以了解下。

本文旨在對(duì)Java反射機(jī)制有一個(gè)全面的介紹,希望通過(guò)本文,大家會(huì)對(duì)Java反射的相關(guān)內(nèi)容有一個(gè)全面的了解。

閱讀本文之前,大家可先行參閱重新理解Java泛型

前言

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

反射基礎(chǔ)

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

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

通過(guò)getClass方法

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

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

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

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

使用.class

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

Class<?> c = String.class;

獲取類(lèi)型信息

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

首先我們?cè)?code>typeinfo.interfacea包下面新建一個(gè)接口A

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

接著我們?cè)?code>typeinfo.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,其中getDeclaredMethod()根據(jù)方法名用于獲取Class類(lèi)指代對(duì)象的某個(gè)方法,然后我們通過(guò)調(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é)果我們可以看出來(lái),不管是public,default,protect還是pricate方法,通過(guò)反射類(lèi)我們都可以自由調(diào)用。當(dāng)然這里我們只是為了顯示反射的強(qiáng)大威力,在實(shí)際開(kāi)發(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è)泛型集合類(lèi)List<Class<? extends Pet>>,我們需要統(tǒng)計(jì)出這個(gè)集合類(lèi)中每種具體的Pet有多少個(gè)。由于Java的泛型擦除,注意類(lèi)似List<? extends Pet>的做法肯定是不行的,因?yàn)榫幾g器做了靜態(tài)類(lèi)型檢查之后,到了運(yùn)行期間JVM會(huì)將集合中的對(duì)象都視為Pet,但是并不會(huì)知道Pet代表的究竟是Cat還是Dog,所以到了運(yùn)行期間對(duì)象的類(lèi)型信息其實(shí)全部丟失了。p.s: 關(guān)于泛型擦除:我在上一篇文章里面有詳細(xì)解釋?zhuān)信d趣的朋友可以看一看。

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

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類(lèi)繼承自Individual,Individual類(lèi)的的實(shí)現(xiàn)稍微復(fù)雜一點(diǎn),我們實(shí)現(xiàn)了Comparable接口,重新自定義了類(lèi)的比較規(guī)則,如果不是很明白的話,也沒(méi)有關(guān)系,我們已經(jīng)將它抽象出來(lái)了,所以不理解實(shí)現(xiàn)原理也沒(méi)有關(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è)抽象類(lèi)PetCreator,以后我們通過(guò)調(diào)用arrayList()方法便可以直接獲取相關(guān)Pet類(lèi)的集合。這里使用到了我們上面沒(méi)有提及的newInstance()方法,它會(huì)返回Class類(lèi)所真正指代的類(lèi)的實(shí)例,這是什么意思呢?比如說(shuō)聲明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;
  }
}

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

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)用來(lái)統(tǒng)計(jì)集合中相關(guān)Pet類(lèi)個(gè)數(shù)的TypeCounter類(lèi)。解釋一下isAssignalbeFrom()方法,它可以判斷一個(gè)反射類(lèi)是某個(gè)反射類(lèi)的子類(lèi)或者間接子類(lèi)。而getSuperclass()顧名思義就是得到某個(gè)反射類(lèi)的父類(lèi)了。

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();
  }
}

總結(jié)

以上就是本文關(guān)于Java反射機(jī)制實(shí)例代碼分享的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:

Java編程打印購(gòu)物小票實(shí)現(xiàn)代碼

Java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解

Java編程實(shí)現(xiàn)月食簡(jiǎn)單代碼分享

如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

  • 關(guān)于JpaRepository的關(guān)聯(lián)查詢(xún)和@Query查詢(xún)

    關(guān)于JpaRepository的關(guān)聯(lián)查詢(xún)和@Query查詢(xún)

    這篇文章主要介紹了JpaRepository的關(guān)聯(lián)查詢(xún)和@Query查詢(xún),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java調(diào)用shell命令并獲取執(zhí)行結(jié)果的示例

    java調(diào)用shell命令并獲取執(zhí)行結(jié)果的示例

    今天小編就為大家分享一篇java調(diào)用shell命令并獲取執(zhí)行結(jié)果的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • MyBatis使用注解開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解

    MyBatis使用注解開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解

    這篇文章主要介紹了MyBatis使用注解開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java中List排序的三種實(shí)現(xiàn)方法實(shí)例

    Java中List排序的三種實(shí)現(xiàn)方法實(shí)例

    其實(shí)Java針對(duì)數(shù)組和List的排序都有實(shí)現(xiàn),對(duì)數(shù)組而言你可以直接使用Arrays.sort,對(duì)于List和Vector而言,你可以使用Collections.sort方法,下面這篇文章主要給大家介紹了關(guān)于Java中List排序的三種實(shí)現(xiàn)方法,需要的朋友可以參考下
    2021-12-12
  • Spring?Boot中@Validated注解不生效問(wèn)題匯總大全

    Spring?Boot中@Validated注解不生效問(wèn)題匯總大全

    這篇文章主要給大家介紹了關(guān)于Spring?Boot中@Validated注解不生效問(wèn)題匯總的相關(guān)資料,@Validated注解是Spring框架中的一個(gè)注解,用于在方法參數(shù)上添加參數(shù)校驗(yàn)規(guī)則,需要的朋友可以參考下
    2023-07-07
  • 最新評(píng)論