概述
Java反射機制指的是在Java程序運行狀態中,對於任何一個類,都可以獲得這個類的所有屬性和方法;對於給定的一個對象,都能夠調用它的任意一個屬性和方法。這種動態獲取類的內容以及動態調用對象的方法稱為反射機制。
意義
(1)反射機制極大的提高了程序的靈活性和擴展性,降低模塊的耦合性,提高自身的適應能力。
(2)通過反射機制可以讓程序創建和控制任何類的對象,無需提前硬編碼目標類。
(3)使用反射機制能夠在運行時構造一個類的對象、判斷一個類所具有的成員變量和方法、調用一個對象的方法。
(4)反射機制是構建框架技術的基礎所在,使用反射可以避免將代碼寫死在框架中。
反射機制的相關類
與Java反射相關的類如下:
與Java反射相關的類如下:
| 類名 | 用途 |
|---|---|
| Class類 | 代表類的實體,在運行的Java應用程序中表示類和接口 |
| Field類 | 代表類的成員變量(成員變量也稱為類的屬性) |
| Method類 | 代表類的方法 |
| Constructor類 | 代表類的構造方法 |
Class類
- 獲得類相關的方法
| 方法 | 用途 |
|---|---|
| asSubclass(Class<U> clazz) | 把傳遞的類的對象轉換成代表其子類的對象 |
| Cast | 把對象轉換成代表類或是接口的對象 |
| getClassLoader() | 獲得類的加載器 |
| getClasses() | 返回一個數組,數組中包含該類中所有公共類和接口類的對象 |
| getDeclaredClasses() | 返回一個數組,數組中包含該類中所有類和接口類的對象 |
| forName(String className) | 根據類名返回類的對象 |
| getName() | 獲得類的完整路徑名字 |
| newInstance() | 創建類的實例 |
| getPackage() | 獲得類的包 |
| getSimpleName() | 獲得類的名字 |
| getSuperclass() | 獲得當前類繼承的父類的名字 |
| getInterfaces() | 獲得當前類實現的類或是接口 |
- 獲得類中屬性相關的方法
| 方法 | 用途 |
|---|---|
| getField(String name) | 獲得某個公有的屬性對象 |
| getFields() | 獲得所有公有的屬性對象 |
| getDeclaredField(String name) | 獲得某個屬性對象 |
| getDeclaredFields() | 獲得所有屬性對象 |
- 獲得類中注解相關的方法
| 方法 | 用途 |
|---|---|
| getAnnotation(Class<A> annotationClass) | 返回該類中與參數類型匹配的公有注解對象 |
| getAnnotations() | 返回該類所有的公有注解對象 |
| getDeclaredAnnotation(Class<A> annotationClass) | 返回該類中與參數類型匹配的所有注解對象 |
| getDeclaredAnnotations() | 返回該類所有的注解對象 |
- 獲得類中構造器相關的方法
| 方法 | 用途 |
|---|---|
| getConstructor(Class...<?> parameterTypes) | 獲得該類中與參數類型匹配的公有構造方法 |
| getConstructors() | 獲得該類的所有公有構造方法 |
| getDeclaredConstructor(Class...<?> parameterTypes) | 獲得該類中與參數類型匹配的構造方法 |
| getDeclaredConstructors() | 獲得該類所有構造方法 |
- 獲得類中方法相關的方法
| 方法 | 用途 |
|---|---|
| getMethod(String name, Class...<?> parameterTypes) | 獲得該類某個公有的方法 |
| getMethods() | 獲得該類所有公有的方法 |
| getDeclaredMethod(String name, Class...<?> parameterTypes) | 獲得該類某個方法 |
| getDeclaredMethods() | 獲得該類所有方法 |
- 類中其他重要的方法
| 方法 | 用途 |
|---|---|
| isAnnotation() | 如果是注解類型則返回true |
| isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定類型注解類型則返回true |
| isAnonymousClass() | 如果是匿名類則返回true |
| isArray() | 如果是一個數組類則返回true |
| isEnum() | 如果是枚舉類則返回true |
| isInstance(Object obj) | 如果obj是該類的實例則返回true |
| isInterface() | 如果是接口類則返回true |
| isLocalClass() | 如果是局部類則返回true |
| isMemberClass() | 如果是內部類則返回true |
Field類
Filed代表類的成員變量(成員變量也稱為類的屬性)。
| 方法 | 用途 |
|---|---|
| equals(Object obj) | 屬性與obj相等則返回true |
| get(Object obj) | 獲得obj中對應的屬性值 |
| set(Object obj, Object value) | 設置obj中對應屬性值 |
Method類
Method代表類的方法。
| 方法 | 用途 |
|---|---|
| invoke(Object obj, Object... args) | 傳遞object對象及參數調用該對象對應的方法 |
Constructor類
Constructor代表類的構造方法。
| 方法 | 用途 |
|---|---|
| newInstance(Object... initargs) | 根據傳遞的參數創建類的對象 |
示例
目錄結構圖

Student.class
package com.lzh.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @author lzh
* create 2019-10-27-10:38
*/
public class Student {
private String name;
private Integer age;
public Student() {
}
private Student(String name){
this.name = name;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Employee.class
package com.lzh.model;
/**
* @author lzh
* create 2019-10-27-16:32
*/
public class Employee {
public void show(){
System.out.println("is show()");
}
}
Employee2
package com.lzh.model;
/**
* @author lzh
* create 2019-10-27-16:32
*/
public class Employee2 {
public void show2(){
System.out.println("is show2()");
}
}
Dog.class
package com.lzh.model;
/**
* @author lzh
* create 2019-10-27-10:36
*/
public class Dog {
private String name;
private Integer age;
public String type;
public Integer height;
private Dog() {
}
private Dog(String name, Integer height) {
this.name = name;
this.height = height;
}
public Dog(String name, String type, Integer height, Integer age) {
this.name = name;
this.type = type;
this.height = height;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", type='" + type + '\'' +
", height=" + height +
'}';
}
}
Teacher.class
package com.lzh.model;
/**
* @author lzh
* create 2019-10-27-16:14
*/
public class Teacher {
public void show1(String s) {
System.out.println("調用了:公有的,String參數的show1(): s = " + s);
}
protected void show2() {
System.out.println("調用了:受保護的,無參的show2()");
}
void show3() {
System.out.println("調用了:默認的,無參的show3()");
}
private String show4(int age) {
System.out.println("調用了,私有的,並且有返回值的,int參數的show4(): age = " + age);
return "abcd";
}
}
測試類,反射可獲取私有屬性和私有方法並進行操作
package com.lzh.classreflect;
import com.lzh.model.Dog;
import com.lzh.model.Student;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author lzh
* create 2019-10-27-10:39
*/
public class TestClass {
@Test
public void getClassTest() {
//1、獲得Class:主要有三種方法:
//第一種方式獲取Class對象
Student student = new Student();
Class stuClass1 = student.getClass();
System.out.println(stuClass1.getName());
//第二種方式獲取Class對象
Class stuClass2 = Student.class;
System.out.println(stuClass2.getName());
System.out.println(stuClass1 == stuClass2);
//第三種方式獲取Class對象
try {
Class stuClass3 = Class.forName("com.lzh.model.Student");//注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名
System.out.println(stuClass3 == stuClass2);//判斷三種方式是否獲取的是同一個Class對象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void isInstanceTest(){
Student student = new Student();
//判斷是否為某個類
System.out.println(student instanceof Student);
}
@Test
public void newObjectTest() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//創建實例:通過反射來生成對象主要有兩種方法
//1.使用Class對象的newInstance()方法來創建Class對象對應類的實例。
Class c = Student.class;
Object stu1 = c.newInstance();
//2.先通過Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建對象,這種方法可以用指定的構造器構造類的實例。
Class<?> stu2 = Student.class;
//通過Class對象獲取指定的Constructor構造器對象
Constructor<?> constructor = stu2.getConstructor(String.class, Integer.class);
Object raicho = constructor.newInstance("raicho", 21);
System.out.println(raicho);
}
@Test
public void getConstructorTest() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
Class<?> stu = Student.class;
//所有"公有的"構造方法
Constructor<?> constructor = stu.getConstructor(String.class, Integer.class);
Object stu1 = constructor.newInstance("raicho_one", 21);
System.out.println(stu1);
System.out.println("----------------------------------");
//獲取所有的構造方法(包括私有、受保護、默認、公有)
Constructor<?>[] constructors=stu.getDeclaredConstructors();
for (Constructor<?> constructor1 : constructors) {
System.out.println(constructor1);
}
//根據構造器創建實例:
Object obj = constructors[0].newInstance("小王",21);
System.out.println(obj);
System.out.println("----------------------------------");
//獲取"某個構造方法"可以是私有的,或受保護、默認、公有;
Constructor<?> declaredConstructor = stu.getDeclaredConstructor(String.class);
//System.out.println("declaredConstructor="+declaredConstructor);
//設置越過安全檢查
declaredConstructor.setAccessible(true);
Object stu2 = declaredConstructor.newInstance("raicho");
System.out.println(stu2);
System.out.println("獲取所有構造器,包括私有");
Constructor<?>[] declaredConstructors = stu.getDeclaredConstructors();
for (Constructor<?> declaredConstructor1 : declaredConstructors) {
System.out.println(declaredConstructor1);
}
System.out.println("----------------------------------");
}
@Test
public void getsetPropertyTest() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> dogClass = Class.forName("com.lzh.model.Dog");
System.out.println("************獲取所有公有的字段********************");
Field[] fields = dogClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("************獲取所有的字段(包括私有、受保護、默認的)********************");
Field[] declaredFields = dogClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("*************設置私有屬性值***********************************");
Constructor<?> declaredConstructor = dogClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Dog dog1 = (Dog) declaredConstructor.newInstance();
System.out.println(dog1);
//dog1.setName("阿拉斯");
Field field = Dog.class.getDeclaredField("name");
field.setAccessible(true);
field.set(dog1,"阿拉斯");
System.out.println(dog1);
}
@Test
public void method() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> teacherClass = Class.forName("com.lzh.model.Teacher");
System.out.println("***************獲取所有的”公有“方法*******************");
Method[] methods = teacherClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("***************獲取所有的方法,包括私有的*******************");
Method[] declaredMethods = teacherClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("***************獲取私有的show4()方法******************");
Method show4 = teacherClass.getDeclaredMethod("show4", int.class);
System.out.println(show4);
Object obj = teacherClass.getConstructor().newInstance();
//越過安全檢查
show4.setAccessible(true);
Object result = show4.invoke(obj, 21);
System.out.println("返回值:"+result);
}
}
通過反射越過集合泛型檢查,為集合添加不同類型的數據
package com.lzh.collectionreflect;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @author lzh
* create 2019-10-27-17:15
*/
public class CollectionTest {
@Test
public void collectionTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//通過反射越過泛型檢查
//有一個String泛型的集合,向這個集合中添加一個Integer類型的值
List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
//list.add(100); //報錯
//獲得集合Class對象
Class listClass = list.getClass();
//獲得add()方法
Method add = listClass.getMethod("add", Object.class);
//調用add()方法
add.invoke(list,100);
for (Object s : list) {
System.out.println(s);
}
}
}
創建pro.properties文件,通過反射
className = com.lzh.model.Employee2 methodName = show2
加載配置文件,通過反射機制創建對象,在不修改代碼的情況下動態修改配置文件創建新對象
package com.lzh.filereflect;
import org.junit.Test;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.ResourceBundle;
/**
* @author lzh
* create 2019-10-27-16:30
*/
public class FileTest {
@Test
public void fileTest() throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.通過反射獲取Class對象
Class<?> employeeclass = Class.forName(getValue("className"));
// String className = getValue("className");
// System.out.println(className);
//2.獲取show()方法
Method method = employeeclass.getMethod(getValue("methodName"));
//3.調用show()方法
method.invoke(employeeclass.getConstructor().newInstance());
//當我們升級這個系統時,不要Student類,而需要新寫一個Student2的類時,這時只需要更改pro.properties的文件內容就可以了。代碼就一點不用改動。
}
public String getValue(String key) throws IOException {
Properties properties = new Properties();
// 使用ClassLoader加載properties配置文件生成對應的輸入流
InputStream in = new FileInputStream("F:\\idea2018WorkSpace\\reflect-mechanism\\src\\main\\java\\com\\lzh\\filereflect\\pro.properties");
// 使用properties對象加載輸入流
properties.load(in);
//獲取key對應的value值
String property = properties.getProperty(key);
return property;
}
}
代碼
github代碼:https://github.com/LZHDonald/reflect-mechanism
參考
百度百科:https://baike.baidu.com/item/JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/6015990?fr=aladdin
