Java筆記之——反射

這篇文章來談?wù)凧ava基礎(chǔ)——反射的內(nèi)容。主要通過以下幾點進(jìn)行介紹:反射機(jī)制、反射的使用及有關(guān)反射的API。

一、反射機(jī)制

反射機(jī)制是Java語言中一個非常重要的特性,它允許程序在運行時進(jìn)行自我檢查,同時也允許對其內(nèi)部的成員進(jìn)行操作。反射機(jī)制能夠?qū)崿F(xiàn)在運行時對類進(jìn)行裝載,因此能夠增加程序的靈活性,但是不恰當(dāng)?shù)厥褂梅瓷錂C(jī)制,也會影響系統(tǒng)的性能。

具體來說,就是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和獲取其屬性。主要是通過反射把類中的各種成分,如成員變量、方法、構(gòu)造方法等信息,映射成一個個的類對象,如Field、Method、Constructor等。

二、反射的基本使用

  1. 獲取Class類的三種方式:
  • 類名.class;
  • 對象名.getClass();
  • Class.forName("要加載的類名")。(這里需要完整的類名,及需要把包也寫進(jìn)來)
  1. 通過上述三種方式獲取到特定類的Class類,即該類的字節(jié)碼后,就可以通過該Class對象獲取構(gòu)造方法對象、方法對象、域?qū)ο蟮取?/li>
  • 通過getConstructor(Class<?>... parameterTypes)獲取構(gòu)造方法對象;
  • 通過getMethod(String name,Class<?>... parameterTypes)獲取方法對象;
  • 通過getField(String name)獲取域?qū)ο蟆?/li>
  1. Constructor、Method、Field的使用
  • 調(diào)用Constructor類的newInstance(Object... initargs)方法可新建對象;
  • 調(diào)用Method類的invoke(Object obj, Object... args)方法調(diào)用對象上相應(yīng)的方法;
  • 調(diào)用Field類的get(Object obj)方法獲得相應(yīng)的域值,調(diào)用set(Object obj, Object value)修改相應(yīng)的域值。

三、舉個栗子

首先定義類:

package com.zhuanget;

public class Animal {

    private int age;
    protected String sex;
    public String name;

    public Animal() {
        this.age = 0;
        this.sex = "male";
        this.name = "animal";
    }

    public Animal(String name) {
        this.age = 0;
        this.sex = "male";
        this.name = name;
    }

    public Animal(String name,String sex) {
        this.age = 0;
        this.sex = sex;
        this.name = name;
    }

    public Animal(String name,String sex,int age) {
        this.age = age;
        this.sex = sex;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name+"正在吃吃吃。");
    }

    public void sleep() {
        System.out.println(name+"正在睡覺?。?!");
    }

    @Override
    public String toString() {
        return "Animal[name:"+name+",age:"+age+",sex:"+sex+"]";
    }
    
    private void owner(String name) {
        System.out.println("owner: "+name);
    }
}

測試類及測試結(jié)果:

public class Test {
    @SuppressWarnings("unchecked")
    public static void main(String[] args){
        try {
            //通過Class.forName()獲取類的Class類
            Class animalClass = Class.forName("com.zhuanget.Animal");
            
            //獲取該類的構(gòu)造器方法類數(shù)組
            Constructor[] animalClassConstructors = animalClass.getConstructors();
            System.out.println("============ constructors =============");
            for (int i = 0; i < animalClassConstructors.length; i++) {
                System.out.println("constructors["+i+"]="+animalClassConstructors[i]);
            }
            //通過參數(shù)類型,這里是String,查找相應(yīng)的構(gòu)造方法,即Animal(String name)構(gòu)造方法
            System.out.println("============ constructor ============");
            Constructor constructor = animalClass.getConstructor(String.class);
            System.out.println("constructor="+constructor);
            
            //獲取該類的所有公有的方法,包括從父類中繼承來的,如java.lang.Object.equals()
            System.out.println("============ methods =============");
            Method[] animalClassMethods = animalClass.getMethods();
            for (int i = 0; i < animalClassMethods.length; i++) {
                System.out.println("methods["+i+"]="+animalClassMethods[i]);
            }


            /**
             * 獲取在該類中定義的所有方法,
             * 包括private、protected、public,
             * 包括重寫父類的,但不包括從父類中繼承來的
             */
            System.out.println("============ declaredMethods =============");
            Method[] declaredMethods = animalClass.getDeclaredMethods();
            for (int i = 0; i < declaredMethods.length; i++) {
                System.out.println("declaredMethods["+i+"]="+declaredMethods[i]);
            }
            
            //獲取類中與相應(yīng)的方法名、方法參數(shù)相對應(yīng)的方法
            System.out.println("=========== method ============");
            Method method = animalClass.getMethod("setAge", int.class);
            System.out.println("method="+method);
            
            //獲取該類的所有公有的域
            System.out.println("============ fields =============");
            Field[] fields = animalClass.getFields();
            for (int i = 0; i < fields.length; i++) {
                System.out.println("fields["+i+"]="+fields[i]);
            }
            
            //獲取該類中所有的域,包括private、protected、public
            System.out.println("============ declaredFields ===========");
            Field[] declaredFiels = animalClass.getDeclaredFields();
            for (int i = 0; i < declaredFiels.length; i++) {
                System.out.println("declaredFields["+i+"]="+declaredFiels[i]);
            }
            
            //獲取該類中域名為name的域類
            System.out.println("========= field =========");
            Field field = animalClass.getField("name");
            System.out.println("field="+field);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

測試結(jié)果:

============ constructors =============
constructors[0]=public com.zhuanget.Animal(java.lang.String,java.lang.String,int)
constructors[1]=public com.zhuanget.Animal(java.lang.String,java.lang.String)
constructors[2]=public com.zhuanget.Animal(java.lang.String)
constructors[3]=public com.zhuanget.Animal()
============ constructor ============
constructor=public com.zhuanget.Animal(java.lang.String)
============ methods =============
methods[0]=public java.lang.String com.zhuanget.Animal.toString()
methods[1]=public java.lang.String com.zhuanget.Animal.getName()
methods[2]=public void com.zhuanget.Animal.setName(java.lang.String)
methods[3]=public void com.zhuanget.Animal.sleep()
methods[4]=public void com.zhuanget.Animal.setAge(int)
methods[5]=public void com.zhuanget.Animal.setSex(java.lang.String)
methods[6]=public int com.zhuanget.Animal.getAge()
methods[7]=public java.lang.String com.zhuanget.Animal.getSex()
methods[8]=public void com.zhuanget.Animal.eat()
methods[9]=public final void java.lang.Object.wait() throws java.lang.InterruptedException
methods[10]=public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
methods[11]=public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
methods[12]=public boolean java.lang.Object.equals(java.lang.Object)
methods[13]=public native int java.lang.Object.hashCode()
methods[14]=public final native java.lang.Class java.lang.Object.getClass()
methods[15]=public final native void java.lang.Object.notify()
methods[16]=public final native void java.lang.Object.notifyAll()
============ declaredMethods =============
declaredMethods[0]=public java.lang.String com.zhuanget.Animal.toString()
declaredMethods[1]=public java.lang.String com.zhuanget.Animal.getName()
declaredMethods[2]=public void com.zhuanget.Animal.setName(java.lang.String)
declaredMethods[3]=public void com.zhuanget.Animal.sleep()
declaredMethods[4]=public void com.zhuanget.Animal.setAge(int)
declaredMethods[5]=public void com.zhuanget.Animal.setSex(java.lang.String)
declaredMethods[6]=public int com.zhuanget.Animal.getAge()
declaredMethods[7]=public java.lang.String com.zhuanget.Animal.getSex()
declaredMethods[8]=public void com.zhuanget.Animal.eat()
declaredMethods[9]=private void com.zhuanget.Animal.owner(java.lang.String)
=========== method ============
method=public void com.zhuanget.Animal.setAge(int)
============ fields =============
fields[0]=public java.lang.String com.zhuanget.Animal.name
============ declaredFields ===========
declaredFields[0]=private int com.zhuanget.Animal.age
declaredFields[1]=protected java.lang.String com.zhuanget.Animal.sex
declaredFields[2]=public java.lang.String com.zhuanget.Animal.name
========= field =========
field=public java.lang.String com.zhuanget.Animal.name

可以看到,由getMethods()方法得到的,是類中public的方法,private void owner(String name)方法未被輸出,同時,Object類中的方法也都被獲取到了;由getDeclaredMethods()方法獲取到的,是該類中聲明的方法,包括private的,父類中的方法并未被輸出。


下面再通過例子說明如何利用Class類實例對象:

public class Test {
    @SuppressWarnings("unchecked")
    public static void main(String[] args){
        try {
            //通過Class.forName()獲取類的Class類
            Class animalClass = Class.forName("com.zhuanget.Animal");
            Object obj = animalClass.newInstance();
            Animal animal = (Animal) obj;
            Field field = animalClass.getField("name");
            field.set(animal,"狗");
            System.out.println(animal);

            Field field2 = animalClass.getDeclaredField("age");
            //解除私有限定,由于age是私有屬性,不加該句會報錯
            field2.setAccessible(true);
            field2.set(animal,3);
            System.out.println(animal);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

運行結(jié)果:

Animal[name:狗,age:0,sex:male]
Animal[name:狗,age:3,sex:male]

四、其他應(yīng)用

通過反射加載配置文件:

  • 類加載器加載配置文件:
InputStream inputStream = Animal.class.getClassLoader()
.getResourceAsStream("conf.properties");

即通過類.class.getClassLoader().getResourceAsStream("配置文件")的形式獲取配置文件輸入流。

  • 類.class.getResourceAsStream()加載,實質(zhì)還是調(diào)用類加載器。截取Class.java的源碼如下:
public InputStream getResourceAsStream(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);//這里依舊是通過類加載器調(diào)用
    }

將conf.properties文件(文件中只定義了className=animal)讀出的過程如下:

InputStream inputStream = Animal.class.getClassLoader().
    getResourceAsStream("conf.properties");//通過類加載器加載,這是相對路徑讀取
InputStream is = Animal.class.
    getResourceAsStream("/conf.properties");//加斜桿,從根路徑找
if (is==null) {
   throw new RuntimeException("file is not found");
}
Properties prop = new Properties();
prop.load(is);
String className = null;
if (prop.containsKey("className")) {
   className = prop.getProperty("className");
}
System.out.println(className);
//運行結(jié)果
"animal"
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容