1. 程式人生 > >Java-反射以及反射呼叫類中方法

Java-反射以及反射呼叫類中方法

認識反射

反射是物件的反射處理操作。

先來看看“正”操作。

在預設情況下,必須要先匯入一個包,而後才能產生類的例項化物件。
如下就是一個正操作。

import java.util.Date;//匯入的包

public class Test{
    public static void main(String[] args){
        Date date = new Date();//產生Date類的例項化物件
        //...使用產生的date引用呼叫類中的方法,屬性
    }
}

而反操作就是根據物件來取得物件的源,反射的核心處理就在於Object類中的一個方法:

取得類的Class物件
public final native Class<?> getClass();
//返回型別為泛型表示可以是任意的Class物件,Class描述的就是一個類。

例如:

import java.util.Date;//匯入的包

public class Test{
    public static void main(String[] args){
        Date date = new Date();//產生Date類的例項化物件

        //反射通過物件獲取到物件的來源
        System.out.println(date.getClass());
    }
}

輸出:

class java.util.Date

通過date.getClass() (物件.getClass())可以得到Class類的物件。

反射的第一步就是拿到Class物件,而拿到Class類物件有三種例項化模式

首先,我想先說一下什麼是Class類,為什麼我們可以通過物件反射得到Class物件,得到Class物件我們能幹什麼。

什麼是Class類
Class類是反射的源頭,也是對整個類的描述,具有相應類的一切資訊。

在Java中一切皆物件,而物件都是由類產生的,也就是Java中有各種各樣的類,而這些類都是同一種類—>Class類。
舉個例子來說:
人,有各種各樣的人 而這些人屬於一類,那就是人類
同理,java類,有各種各樣的類, 而這些類屬於同一類,那就是Class類。

區分: class是關鍵字,定義類時使用,Class是類名

一個類被類載入器載入到記憶體中佔用一片儲存空間,這個空間中的內容稱為類的位元組碼,不同的類的位元組碼是不同的,所以他們在記憶體中的內容是不同的,而各個位元組碼可以用不同的Class類物件來表示。

比如:Date date = new Date();
當使用到Date類時,類載入器會將Date類載入到記憶體中,以位元組碼的形式存在。而Date.getClass();就是得到屬於Date的那份位元組碼,返回Date類。每個類中包含的屬性是類的名字,類的訪問屬性,類所屬的包名等等。所以當列印Date.getClass()時打印出的就是Date的訪問屬性,Date的所屬包名。

Class類的三種例項化方式:

1.物件.getClass();//取得Class物件
2.類名.class;//可以直接根據某個具體類來取得其Class物件
3.呼叫Class類的靜態方法Class.forName(String className)傳入類的全名稱來取得其Class物件。
比如:Class<?> cls = Class.forName(“java.util.Date”);

使用:

Class<?> cls1 = date.getClass();
Class<?> cls = Class.forName("java.util.Date");
Class<?> cls2 = Date.class;

Class類物件可以通過反射例項化物件

方法:
public T newInstance() throws InstantiationException,IllegalAccessException

使用:
Object obj = cls.newInstance();
就相當於new了一個物件

Class類物件能幹什麼
得到Class物件,就可以根據物件獲取到類中的變數,方法,構造等資訊。獲取這些資訊有相應的方法。

反射與類的操作

取得類的包名稱:public Package getPackage()
取得父類的Class物件:public native Class<? super T>getSuperclass();
取得實現的父介面:public Class<?>[] getInterfaces()

Class<?> cls = Watermelon.class;
System.out.println(cls.getPackage().getName());//包名
System.out.println(cls.getSuperclass().getName());//父類名
Class<?>[] str = cls.getInterfaces();
for(Class<?> str1:str){
    System.out.printf(str1.getName());//父介面名
}

反射呼叫類中構造方法

取得類中指定引數型別的構造

public Constructor getConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException
只能取得類中public許可權的構造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)
可以取得類中全部構造方法,包含私有構造

取得類中所有構造方法

public Constructor<?>[] getConstructors() throws SecurityException
只能取得類中public許可權的構造方法
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
可以取得類中全部構造方法,包含私有構造

舉例:

class Person{
    public Person(){};
    public Person(int n){ };
    public Person(String name,int age){};
    private Person(String name,String name1){};

}

public class Test{
    public static void main(String[] args) throws Exception {
        //1.取得Class類的物件
        Class<?> cls = Person.class;
        //取得類中所有public許可權的構造
        System.out.println("getConstructors();取得類中所有public許可權構造");
        Constructor<?>[] constructors = cls.getConstructors();
        for(Constructor<?> constructor : constructors){
            System.out.println(constructor);
        }

        //取得類中全部構造
        System.out.println("getDeclaredConstructors();取得類中所有構造");
        constructors = cls.getDeclaredConstructors();
        for(Constructor<?> constructor :constructors){
            System.out.println(constructor);
        }

        //取得類中指定引數構造,public許可權
        System.out.println("getConstructor(String.class,int.class);取得指定引數的構造,public許可權");
        Constructor<?> constructor = cls.getConstructor(String.class,int.class);
        System.out.println(constructor);

        //取得類中指定引數構造,所有許可權
        System.out.println("getDeclaredConstructor(String.class,String.class);取得指定引數的構造,所有許可權");
        constructor = cls.getDeclaredConstructor(String.class,String.class);
        System.out.println(constructor);
    }
}

結果:

getConstructors();取得類中所有public許可權構造
public www.bit.java.Person(java.lang.String,int)
public www.bit.java.Person(int)
public www.bit.java.Person()
getDeclaredConstructors();取得類中所有構造
private www.bit.java.Person(java.lang.String,java.lang.String)
public www.bit.java.Person(java.lang.String,int)
public www.bit.java.Person(int)
public www.bit.java.Person()
getConstructor(String.class,int.class);取得指定引數的構造,public許可權
public www.bit.java.Person(java.lang.String,int)
getDeclaredConstructor(String.class,String.class);取得指定引數的構造,所有許可權
private www.bit.java.Person(java.lang.String,java.lang.String)

可以使用Constructor類例項化物件

class Person{
    private String name;
    private int age;
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    };

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Test{
    public static void main(String[] args) throws Exception {
        //1.取得Class類的物件
        Class<?> cls = Person.class;
        Constructor<?> constructor = cls.getConstructor(String.class,int.class);
        System.out.println(constructor.newInstance("abaka",21));
    }
}

結果:
Person{name=‘abaka’, age=21}

反射呼叫普通方法

取得類中指定名稱的普通方法

public Method getMethod(String name, Class<?>… parameterTypes)
//方法有過載所以要傳名稱和引數型別取得本類以及父類中所有public方法
public Method getDeclaredMethod(String name, Class<?..parameterTypes)
取得本類中全部普通方法,包括私有方法

取得類中全部普通方法

public Method[] getMethods() throws SecurityException
取得本類以及父類中所有public方法
public Method[] getDeclaredMethods() throws SecurityException
取得本類中全部普通方法,包括私有方法

Method類中提供呼叫類中普通方法的API

public Object invoke(Object obj, Object… args)//具體物件, 具體物件的值

//1.取得Class類的物件
Class<?> cls = Person.class;
//2.取得本類以及父類中所有public方法
Method[] methods = cls.getMethods();
for(Method method:methods){
    System.out.println(method);
}

應用:

class Person{
    private String name;
    private int age;
    public void setName(String name){
        this.name = name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


}

public class Test{
    public static void main(String[] args) throws Exception {
        //1.取得Class類的物件
        Class<?> cls = Person.class;
        //2.建立Person例項化物件
        Person person = (Person)cls.newInstance();
        //3.取得方法,拿到setName的Method物件
        Method method = cls.getMethod("setName",String.class);
        Method method1 = cls.getMethod("setAge", int.class);
        //4.通過invoke進行呼叫
        method.invoke(person,"abaka");
        method1.invoke(person,21);
        System.out.println(person);

    }
}

反射呼叫類中屬性Filed
取得類中指定屬性

public Field getField(String name)throws NoSuchFieldException, SecurityException
取得本類以及父類中所有public屬性
public Field getDeclaredField(String name)throws NoSuchFieldException, SecurityException
取得本類中全部普通屬性,包含私有屬性。

取得類中全部屬性

public Field[] getFields() throws SecurityException
public Field[] getDeclaredFields() throws SecurityException

設定屬性

public void set(Object obj, Object value)

取得屬性

public Object get(Object obj) throws IllegalArgumentException,IllegalAccexxException

取得屬性的型別

public Class<?> getType()

使用:


//1.先建立class物件Class<?> cls = Person.class;
//2.建立Person例項化物件
Person person = (Person)cls.newInstance();
Field field = cls.getField("name");
field.set(person,"abaka");
System.out.println(field.get(person));