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