Java中的反射到底是個啥?
前言
最近看面試題的時候,看到有關反射的面試,由於上課學的時候老師壓根沒講反射的內容,所以今天又來補漏洞啦
一、反射是什麼
反射到底是個啥?《Java核心技術》書中給出的解釋是:能夠分析類能力的程式稱為反射。反射機制可以用來:
- 在執行時分析類的能力
- 在執行時檢視物件,例如,編寫一個toString
- 實現通用的陣列操作程式碼
- 利用Method物件,這個物件很像C++中的函式指標
通俗來說,反射就是在執行時才知道要操作的類是什麼,並且可以在執行時獲取類的完整構造,並呼叫對應的方法。
因此,反射是一種功能強大且複雜的機制。使用它的主要人員是工具構造者,而不是應用程式設計師。
二、類物件
- 類的物件:基於某個類new出來的物件,也稱為例項物件。
- 類物件:類載入的產物,封裝了一個類的所有資訊(類名、父類、介面、屬性、方法、構造方法)
也就是說,每個類載入到記憶體都對應一個Class物件,每個類有且只有一個Class物件
顯示當前程式所載入的類:JVM引數-verbose:class
三、獲取類物件
3.1 通過類的物件,獲取類物件
/**
* @author: Radish
* @date: 2020-10-07 19:10
*/
public class TestPerson {
public static void main(String[] args) {
Person person = new Person("張三");
Class<?> aClass = person.getClass();
System.out.println(aClass);
}
}
3.2 通過類名獲取類物件
/**
* @author: Radish
* @date: 2020-10-07 19:10
*/
public class TestPerson {
public static void main(String[] args) {
System.out.println(Person.class);
}
}
3.3 通過靜態方法獲取類物件(推薦)
/**
* @author: Radish
* @date: 2020-10-07 19:10
*/
public class TestPerson {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass = Class.forName("com.reflect.Person");
}
}
若類名不存在,則會丟擲異常
3.4 常用方法
使用反射獲取類的構造方法,建立物件
//使用反射獲取類的構造方法,建立物件
public static void reflectOpe2() throws Exception {
//(1)獲取類物件
Class<?> aClass = Class.forName("com.reflect.Person");
//(2)獲取類的構造方法Constructor
System.out.println("===========獲取類的構造方法============");
Constructor<?>[] cons = aClass.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
//(3)獲取類中的無參構造
System.out.println("===========獲取類的無參構造============");
Constructor<?> con = aClass.getConstructor();
System.out.println(aClass);
Person lisi = (Person) con.newInstance();
System.out.println(lisi);
//(4)獲取類中帶參構造方法
System.out.println("===========獲取類的帶參構造============");
Constructor<?> con1 = aClass.getConstructor(String.class, int.class);
Person p2 = (Person) con1.newInstance("李四", 23);
System.out.println(p2);
}
使用反射獲取類中的方法,並呼叫方法
//3使用反射獲取類中的方法,並呼叫方法
public static void reflectOpe3() throws Exception {
//(1)獲取類物件
Class<?> aClass = Class.forName("com.reflect.Person");
//(2)獲取方法Method物件
System.out.println("========獲取方法Method物件========");
//Method[] methods = aClass.getMethods(); 獲取公開的方法,包括從父類繼承的方法
Method[] methods = aClass.getDeclaredMethods(); //獲取類中的所有方法,包括私有、預設、保護的、不包含繼承的方法
for (Method method : methods) {
System.out.println(method);
}
//(3)獲取單個方法
System.out.println("===========獲取單個方法===========");
System.out.println("----------不帶參----------");
Method eatMethod = aClass.getMethod("eat");
//呼叫方法
//正常呼叫方法 Person person = new Person(); person.eat;
Person zhangsan = (Person) aClass.newInstance();
eatMethod.invoke(zhangsan);
//toString
Method toStringMethod = aClass.getMethod("toString");
Object result = toStringMethod.invoke(zhangsan);
System.out.println(result);
System.out.println("----------帶參----------");
Method eatMethod2 = aClass.getMethod("eat", String.class);
eatMethod2.invoke(zhangsan, "雞腿");
//(4)獲取私有方法
System.out.println("===========獲取私有方法===========");
Method privateMethod = aClass.getDeclaredMethod("privateMethod");
//設定訪問許可權無效
privateMethod.setAccessible(true);
privateMethod.invoke(zhangsan);
//(5)獲取靜態方法
System.out.println("===========獲取靜態方法===========");
Method staticMethod = aClass.getMethod("staticMethod");
staticMethod.invoke(null);
}
這裡需要注意幾點:①getMethods方法是獲取公開的方法,包括從父類繼承的方法;getDeclaredMethods方法是獲取類中的所有方法,包括私有、預設、保護的、不包含繼承的方法。②在獲取私有方法時,需設定訪問許可權無效Method setAccessible(true)
使用反射實現一個可以呼叫任何物件方法的通用方法
//4使用反射實現一個可以呼叫任何物件方法的通用方法
public static Object invokeAny(Object obj, String methodName, Class<?>[] types,Object...args) throws Exception {
//1獲取類物件
Class<?> aClass = obj.getClass();
//2獲取方法
Method method = aClass.getMethod(methodName, types);
//3呼叫
return method.invoke(obj,args);
}
public static void main(String[] args) throws Exception {
//reflectOpe2();
//reflectOpe3();
Properties properties = new Properties();
invokeAny(properties, "setProperty", new Class[]{String.class,String.class}, "username", "張三");
System.out.println(properties);
}
使用反射獲取類的屬性
//5使用反射獲取類的屬性
public static void reflectOpe4() throws Exception{
//(1)獲取類物件
Class<?> aClass = Class.forName("com.reflect.Person");
//(2)獲取屬性(欄位) 公開的欄位,父類繼承的欄位
// Field[] fields = aClass.getFields();
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//(3)獲取name屬性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
System.out.println(name);
//(4)賦值
Person zhangsan = (Person) aClass.newInstance();
name.set(zhangsan, "張三");
//(5)獲取值
System.out.println(name.get(zhangsan));
}
四、設計模式
4.1 什麼是設計模式
一套被反覆呼叫、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。
- 好處:使用設計模式為了可重用程式碼、讓程式碼更容易被他人理、保證程式碼可靠性、重用性。
4.2 工廠設計模式
- 工廠設計模式主要負責物件建立的問題
- 開發中有一個非常重要的原則“開閉原則”,對擴充套件開放、對修改關閉。
- 可通過反射進行工廠模式的設計,完成動態的物件建立。
新增實現類時只需修改配置檔案
4.3 單例模式
- 單例:只允許建立一個該類的物件。
方式1:餓漢式(類載入時建立,天生執行緒安全)
class Singleton {
private static final Singleton = new Singleton();
private Singleton();
public static Singleton getInstance(){
return instance;
};
}
方式2:懶漢式(使用時建立,執行緒不安全,加同步,效率低)
class Singleton {
private static final Singleton = null;
private Singleton();
public static synchronized Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
};
}
方式3:懶漢式(使用時建立,執行緒安全)
class Singleton {
private Singleton();
private static class Holder() {
static Singleton s = new Singleton();
}
public static Singleton instance(){
return Holder.s;
};
}
五、列舉
5.1 什麼是列舉
列舉是一個引用型別,列舉是一個規定了取值範圍的資料型別。
- 列舉變數不能使用其他的資料,只能使用列舉中常量賦值,提高程式安全性。
- 定義列舉使用enum關鍵字。
- 列舉的本質:
- 列舉是一個終止類,並整合enum抽象類
- 列舉中常量是當前型別的靜態常量
六、註解
6.1 什麼是註解
註解是程式碼裡的特殊標記,程式可以讀取註解,一般用於替代配置檔案。
-
開發人員可以通過註解告訴類如何執行。
- 在Java技術裡註解的典型應用是:可以通過反射技術去得到類裡面的註解,以決定怎麼去執行類。
-
常見註解:@Override、@Deprecated
-
定義註解使用@interface關鍵字,註解中只能包含屬性
定義一個註解:
使用
6.2 註解屬性型別
- String型別
- 基本資料型別
- Class型別
- 列舉型別
- 註解型別
- 以上型別的一堆陣列
6.3 元註解
-
元註解:用來描述註解的註解
-
@Retention:用於指定註解可以保留的域。
- RetentionPolicy.CLASS:註解記錄在class檔案中,執行java程式時,JVM不會保留
- RetentionPolicy.RUNTIME:註解記錄在class檔案中,執行java程式時,JVM會保留,程式可以通過反射獲取該註釋
- RetentionPolicy.SOURCE:編譯時直接丟棄這種策略的註釋。
-
@Target:指定註解用於修飾類的哪個成員
相關文章
- Java築基 - JNI到底是個啥Java
- Webhook到底是個啥?WebHook
- 計算機中的流水線技術到底是個啥?計算機
- [譯] Flutter 元件到底是個啥?Flutter元件
- 【Flutter脫髮錄】RenderObject到底是個啥?FlutterObject
- 傳說中 VUE 的“語法糖”到底是啥?Vue
- 淺談java中的反射Java反射
- Java 中的 反射機制Java反射
- 你常常看到的 __init__.py 到底是個啥?
- Java中的反射機制(二) 一個利用反射進行物件拷貝的例子Java反射物件
- Java中的類反射機制Java反射
- 一文帶你搞懂 RPC 到底是個啥RPC
- 下一個時代的發展架構竟然是它!FaaaaaaaaS到底是個啥?架構
- 關於Java中的反射機制Java反射
- java中的反射機制淺析Java反射
- JAVA中的反射機制詳解Java反射
- 資料分析師到底是幹啥的?
- Java的反射Java反射
- Java中的反射技術--小白新手向Java反射
- java反射——反射AnnotationJava反射
- JavaScript當中的this究竟是個啥?JavaScript
- Java反射機制demo(五)—獲得並呼叫一個類中的方法Java反射
- Java 方法的反射Java反射
- Java中反射的概述及瞭解ClassLoaderJava反射
- java反射(3)在工廠模式中的使用Java反射模式
- Java物件在JVM中長啥樣Java物件JVM
- 2022 年最受矚目的新特性 CSS @layer 到底是個啥?CSS
- 小米智慧腳踏車之後又發奇招 這個到底是啥?
- 【Java 反射學習】Java 反射基礎Java反射
- [Java 反射學習] Java 反射基礎Java反射
- Java 中經常被提到的 SPI 到底是什麼?Java
- [PHP 原始碼] EXPECTED 和 UNEXPECTED 到底是啥?PHP原始碼
- Java 反射Java反射
- Java——反射Java反射
- Java反射Java反射
- Java反射以及在Android中的特殊應用Java反射Android
- Java中物件的動態建立及其反射機制Java物件反射
- Java反射—初探反射基礎Java反射