反射入門篇幅有點長,但我不想打散了,因爲只看其中一部分也沒啥意義,所以分爲了上中下3篇,寫的不好的方面,希望大家指出
簡介
反射能幹什麼?你只需要給我一個類的地址,我就能知道類的全部信息(類名稱、父類、繼承的接口、方法、屬性、甚至實例化並賦值),那麼下面我們就來看看它怎麼辦到的吧!
預備工作
這次我們準備用了一個Customer類,我們把它當成反射的對象,我們希望通過反射獲取它的全部信息,我們先來看看這個類吧!
- Customer類,(包名有點隨意了):
- (注意,下面要用)有一個無參數構造方法和一個private的構造方法
- 爲了方便後面測試效果,實現了Person接口,但是Person接口沒有抽象方法
package com.bridge.security.util.bean;
/**
* @創建人 zhangtaiyuan
* @創建時間 2020/7/2
* @描述
*/
public class Customer implements Person{
private String name;
private String email;
private int age;
public Customer() { }
private Customer(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", age='" + age + '\'' +
'}';
}
}
- 什麼也沒做的Person接口
package com.bridge.security.util.bean;
public interface Person { }
上面準備好了,我們就可以通過反射獲取Customer類信息了
獲得Class信息
獲得對象信息之前,我們必須獲得Class信息,然後從Class中獲取類對應的信息,獲取Clss有3種方法,如下:
- 通過實體類獲得
Customer customer = new Customer() ; // 已經存在有指定類的實例化對象
Class<? extends Customer> cls = customer.getClass() ;
System.out.println(cls.getName()); //輸出結果:com.bridge.security.util.bean.Customer
- 直接從XXX.class獲得
Class<? extends Customer> cls = Customer.class;
System.out.println(cls.getName()); //輸出結果:com.bridge.security.util.bean.Customer
- 從類的路徑獲得
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(cls.getName());//輸出結果:com.bridge.security.util.bean.Customer
上面3個方式獲得的Class都一樣,最後一個通過傳入String就能獲得Class對象,是不是讓我們想起了JDBC,哈哈
通過Class獲得各種屬性
通過Class實例化對象
- 在JDK9之前:
class.newInstance()
(jDK9開始不建議使用這個方法了) - 在JDK9之後:
clazz.getDeclaredConstructor().newInstance()
- 大部分公司還在用jdk8,所以例子用的9之前的方式:
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
Object obj = cls.newInstance() ; // 實例化對象,JDK 9後被廢除了
//Object obj = cls.getDeclaredConstructor().newInstance() ; JDK 9之後才能用
System.out.println(obj); // 由於沒有賦值:輸出的都是null 輸出結果:Customer{name='null', email='null', age='0'}
- 看着上面,你是不是明白了,如果沒有反射,那麼工廠模式創建實現類時,就會出現很多判斷語句,並且當有新的工廠的實現類時,你就得修改代碼並且升級版本,所以,沒有反射,這種設計模式幾乎不可能實現的(維護太麻煩)
通過Class獲取屬性
- 獲得包路徑:public Package getPackage();//比下面多一個“package”
- 獲得包路徑:public Package getPackageName();
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(cls.getPackage()); // package com.bridge.security.util.bean
System.out.println(cls.getPackageName()); // com.bridge.security.util.bean
- 獲得父類:public Class<? super T> getSuperclass()
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
Class superclass = cls.getSuperclass();// 返回的是class
System.out.println(superclass);// class java.lang.Object
- 獲得接口:public Class<?>[] getInterfaces()
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
for (Class<?> inter:clazz.getInterfaces()){ //獲得接口,是一個class數組
System.out.println(inter.getName()); //com.bridge.security.util.bean.Person
}
- 構造方法
-
獲取所有構造方法:public Constructor<?>[] getDeclaredConstructors()
-
獲取指定的構造方法:public Constructor getDeclaredConstructor(Class<?>… parameterTypes)
-
獲取所有公開的構造方法:public Constructor<?>[] getConstructors()
-
獲取公開的指定構造方法:public Constructor getConstructor(Class<?>… parameterTypes)
- 全部構造方法
-
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
for (Constructor<?> constructor:clazz.getDeclaredConstructors()){ //獲得所有構造方法,包括非公開的 Customer中有個private方法
System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes()));
}
/**
* 下面是輸出結果
* com.bridge.security.util.bean.Customer[]
* com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
*/
- 指定構成方法
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(clazz.getDeclaredConstructor().getName() + Arrays.toString(clazz.getDeclaredConstructor().getParameterTypes()));
//下面是獲得private 的夠着方法
System.out.println(clazz.getDeclaredConstructor(String.class,String.class,int.class).getName() + Arrays.toString(clazz.getDeclaredConstructor(String.class,String.class,int.class).getParameterTypes()));
/**
* 輸出結果:
* com.bridge.security.util.bean.Customer[]
* com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
*/
- 公開的構造方法,下面就沒有private構造方法了
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
for (Constructor<?> constructor:clazz.getConstructors()){ //獲得所有構造方法,包括非公開的 Customer中有個private方法
System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes()));
}
/**
* 下面是輸出結果
* com.bridge.security.util.bean.Customer[]
*/
- 指定的公開的構造方法,下面嘗試去獲得private的構造方法,就會直接報錯
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(clazz.getConstructor().getName() + Arrays.toString(clazz.getConstructor().getParameterTypes()));
//下面是獲得private 的夠着方法
System.out.println(clazz.getConstructor(String.class,String.class,int.class));
/**
* 輸出結果:
* com.bridge.security.util.bean.Customer[]
* Exception in thread "main" java.lang.NoSuchMethodException: com.bridge.security.util.bean.Customer.<init>(java.lang.String, java.lang.String, int)
* at java.base/java.lang.Class.getConstructor0(Class.java:3322)
* at java.base/java.lang.Class.getConstructor(Class.java:2108)
* at com.bridge.security.util.bean.TestDemo.main(TestDemo.java:16)
*/
總結
反射提供了另外一種設計思路,比如工廠模式,很多框架軟件裏都能看到它應用場景,比如:JDBC
未完…… 還有反射入門(中、下)