Java 反射機制是指在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性。這種動態獲取信息以及動態調用對象方法的功能稱為 Java 語言的反射機制。
簡單來說,一個類包含成員變量、方法、構造方法等組成部分。反射就是加載類,並解析出類的各個組成部分。
在 Java 中,Class 類用於表示某個類的字節碼。獲取 Class 對象主要有三種途徑:
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 方式一:Class.forName()
Class clazz = Class.forName("dsa.Person");
// 方式二:對象.getClass()
Class clazz1 = new Person().getClass();
// 方式三:類名.class
Class clazz2 = Person.class;
}
}
通過 Constructor 類可以獲取類的構造方法並實例化對象。
getConstructor(Class... parameterTypes):獲取指定參數類型的 public 構造方法。getDeclaredConstructor(Class... parameterTypes):獲取指定參數類型的 所有聲明 構造方法(包含 private)。setAccessible(true) 進行「暴力破解」後才能調用。public class Person {
public Person() { System.out.println("無參構造"); }
public Person(String name) { System.out.println(name); }
public Person(String name, int pwd) { System.out.println(name + "+" + pwd); }
private Person(List list) { System.out.println("List"); }
}
@Test
public void testPublicNoArg() throws Exception {
Class clazz = Class.forName("ReflectDemo.Person");
Constructor cr = clazz.getConstructor(null);
Person p = (Person) cr.newInstance(null);
}
@Test
public void testPublicWithArgs() throws Exception {
Class clazz = Class.forName("ReflectDemo.Person");
Constructor cr = clazz.getConstructor(String.class);
Person p = (Person) cr.newInstance("haha");
}
@Test
public void testPrivateConstructor() throws Exception {
Class clazz = Class.forName("ReflectDemo.Person");
Constructor cr = clazz.getDeclaredConstructor(List.class);
cr.setAccessible(true); // 暴力破解
Person p = (Person) cr.newInstance(new ArrayList());
}
通過 Method 類調用類的方法:
getMethod(String name, Class... parameterTypes):獲取 public 方法(包含繼承)。getDeclaredMethod(String name, Class... parameterTypes):獲取聲明的方法(不包含繼承,可獲取 private)。invoke(Object obj, Object... args),靜態方法傳 null 作為對象。// 反射 public void jf()
Method method = clazz.getMethod("jf", null);
method.invoke(p, null);
// 反射 public static void jf(int num)
Method method = clazz.getMethod("jf", int.class);
method.invoke(null, 30); // 靜態方法對象傳 null
// 反射 private 方法
Method method = clazz.getDeclaredMethod("jf", InputStream.class);
method.setAccessible(true);
method.invoke(p, new FileInputStream("d:\\qqClient.txt"));
通過 Field 類操作類的成員變量:
getField(String name):獲取 public 字段(包含繼承)。getDeclaredField(String name):獲取聲明的字段(包含 private,不包含繼承)。setAccessible(true)。null。// public 字段
Field f = clazz.getField("name");
Object value = f.get(p);
f.set(p, "newName");
// private 字段
Field f = clazz.getDeclaredField("password");
f.setAccessible(true);
f.set(p, 36);
// private static 字段
Field f = clazz.getDeclaredField("age");
f.setAccessible(true);
f.set(null, 24); // 靜態字段對象傳 null
反射機制雖然強大,但會破壞封裝性,且有一定性能開銷。實際開發中常用於框架設計(如 Spring、MyBatis)、註解處理、動態代理等場景。掌握反射的核心 API(Class、Constructor、Method、Field)及其獲取與調用方式,是 Java 進階開發的必備技能。