目錄
- 一、反射概述
- 二、擷取Class類對象的三種方法
- 三、Class對象功能
-
- (1)Field類
-
- 1.1 擷取成員變量
- 1.2 成員變量操作
- (2)Constructor類
-
- 2.1 擷取構造方法
- 2.2 構造方法操作
- (3)Method類
-
- 3.1 擷取方法
- 3.2 方法操作
- 四、執行個體
-
- (1)通過配置檔案運作方法
- 五、反射與注解
-
- (1)注解
-
- 1.1 内置注解
- 1.2 元注解
- (2)自定義注解
- (3)注解與反射
一、反射概述
反射:把類中的各個組成部分映射成一個個的對象(指在程式的運作狀态中,可以構造任意一個類的對象,可以了解任意一個對象所屬的類,可以了解任意一個類的成員變量和方法,可以調用任意一個對象的屬性和方法。)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0DMXJmdK1mYwhnMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmLxAjM4ETNxEjM4ADNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
二、擷取Class類對象的三種方法
- Class.forName(“全類名”)
- 類名.class
- 對象.getClass()
一個類無論建立多少個執行個體對象,其依據的都是用一個Class對象
Class類實際上是一個泛型類,不過他将已經抽象的概念複雜化了,故忽略類型參數,使用原始的Class類
代碼示例:
package test;
public class ReflectiveDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 第一種
String st="test.Employee"; // 包名.類名
Class class1=Class.forName(st);// 需抛出異常
// 第二種
Class class2=Employee.class;
// 第三種
Employee e = new Employee() ;
Class class3= e.getClass();
}
}
三、Class對象功能
Person類 代碼示例:
package testa;
public class Person {
public String a="aa";
String b="bb";
protected String c="cc" ;
private String d="dd";
public Person() {
}
public Person(String a, String b) {
this.a = a;
this.b = b;
}
public void eat() {
System.out.println("eat");
}
public void eat(String a) {
System.out.println("eat"+a);
}
@Override
public String toString() {
return "Person [a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + "]";
}
}
(1)Field類
1.1 擷取成員變量
java.lang.Class
方法 | 說明 |
---|---|
Field[] getFields() | 擷取所有public修飾的成員變量們 |
Field getField(String name) | 擷取指定名稱的public修飾的成員變量 |
Field[] getDeclaredFields() | 擷取所有的成員變量們 |
Field getDeclaredField(String name) | 擷取指定名稱的成員變量 |
代碼示例:
import java.lang.reflect.*;
public class ReflectiveDemo {
public static void main(String[] args) throws Exception {
Class class1=Person.class;
// 擷取所有public成員變量
Field[] fields = class1.getFields();
// 擷取指定public成員變量
Field field = class1.getField("a");
// 擷取所有成員變量
Field[] declaredFields = class1.getDeclaredFields();
// 擷取指定成員變量
Field declaredField = class1.getDeclaredField("c");
}
}
1.2 成員變量操作
java.lang.reflect.Field
方法 | 說明 |
---|---|
Object get(Object obj) | 擷取值 |
void set(Object obj, Object value) | 設定值 |
非private代碼示例:
Class class1=Person.class;
Person person1= new Person();
Field declaredField = class1.getDeclaredField("a"); //擷取非private成員變量
// 設定值
declaredField.set(person1, "aaa");
// 擷取值
Object result1 = declaredField.get(person1);
System.out.println(result1);
在擷取和設定非private成員變量時,無任何差錯。但換成private成員變量時卻報錯了
隻需忽略通路修飾符的安全檢查
setAccessible(true);
即可解決問題。
private代碼示例:
Class class1=Person.class;
Person person1= new Person();
Field declaredField = class1.getDeclaredField("d"); //擷取private成員變量
declaredField.setAccessible(true); // 暴力反射
// 設定值
declaredField.set(person1, "ddd");
// 擷取值
Object result1 = declaredField.get(person1);
System.out.println(result1);
(2)Constructor類
2.1 擷取構造方法
java.lang.Class
方法 | 說明 |
---|---|
Constructor<?>[] getConstructors() | 擷取所有public修飾的構造方法 |
Constructor< T> getConstructor(類<?>… parameterTypes) | 擷取指定public修飾的構造方法 |
Constructor<?>[] getDeclaredConstructors() | 擷取所有構造方法 |
Constructor< T> getDeclaredConstructor(類<?>… parameterTypes) | 擷取指定構造方法 |
代碼示例:
Class class1=Person.class;
// 擷取所有public構造方法
Constructor[] constructors = class1.getConstructors();
// 擷取指定public構造方法
Constructor constructor = class1.getDeclaredConstructor(String.class,String.class);
2.2 構造方法操作
java.lang.reflect.Constructor
方法 | 說明 |
---|---|
T newInstance(Object… initargs) | 建立對象 |
建立無參對象時使用java.lang.Class中的newInstance() 方法
Class class1=Person.class;
// 有參對象
Constructor constructor = class1.getDeclaredConstructor(String.class,String.class);
Object person1 = constructor.newInstance("aaa","bbb");
//無參對象
Object person2 = class1.newInstance();
(3)Method類
3.1 擷取方法
java.lang.Class
方法 | 說明 |
---|---|
Method[] getMethods() | 擷取所有public方法(包括超類) |
Method getMethod(String name, 類<?>… parameterTypes) | 擷取指定public方法 |
Method[] getDeclaredMethods() | 擷取所有方法(包括超類) |
Method **getDeclaredMethod(String name, 類<?>… parameterTypes) | 擷取指定方法 |
代碼示例:
Class class1=Person.class;
// 所有public方法
Method[] methods = class1.getMethods();
// 指定pubilc方法
Method method1 =class1.getMethod("eat",String.class);
Method method2 =class1.getMethod("eat");
3.2 方法操作
java.lang.reflect.Method
方法 | 說明 |
---|---|
Object invoke(Object obj, Object… args) | 執行方法 |
代碼示例:
Class class1=Person.class;
Person person= new Person();
// 有參方法
Method method1 = class1.getMethod("eat",String.class);
Object person1 = method1.invoke(person, "黃金開口笑");
// 無參方法
Method method2=class1.getMethod("eat");
Object person2 = method2.invoke(person);
四、執行個體
(1)通過配置檔案運作方法
配置檔案pro.properties
代碼示例:
package testa;
import java.io.InputStream;
import java.lang.reflect.*;
import java.util.Properties;
public class ReflectiveDemo {
public static void main(String[] args) throws Exception {
// 加載配置檔案
Properties pro= new Properties();
ClassLoader classLoader = ReflectiveDemo.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
pro.load(resourceAsStream);
// 擷取配置檔案資訊
String className = pro.getProperty("className");
String methodNmae = pro.getProperty("methodName");
// 加載類進記憶體
Class class1 = Class.forName(className);
// 建立對象
Object obj = class1.newInstance();
// 擷取方法對象
Method method=class1.getMethod(methodNmae,String.class);
// 執行方法
method.invoke(obj,"麥辣雞腿堡");
}
}
五、反射與注解
(1)注解
1.1 内置注解
@Override
- 檢查該方法是否是重寫方法。
@Deprecated
- 标記過時方法。
@SuppressWarnings
- 抑制編譯器警告。
1.2 元注解
@Target
- 标記這個注解應該是哪種 Java 成員。
public enum ElementType {
TYPE, /* 類、接口(包括注釋類型)或枚舉聲明 */
FIELD, /* 字段聲明(包括枚舉常量) */
METHOD, /* 方法聲明 */
PARAMETER, /* 參數聲明 */
CONSTRUCTOR, /* 構造方法聲明 */
LOCAL_VARIABLE, /* 局部變量聲明 */
ANNOTATION_TYPE, /* 注釋類型聲明 */
PACKAGE /* 包聲明 */
}
@Retention
- 辨別這個注解怎麼儲存,是隻在代碼中,還是編入class檔案中,或者是在運作時可以通過反射通路。(一般定義為RUNTIME)
public enum RetentionPolicy {
SOURCE, /* Annotation資訊僅存在于編譯器處理期間,編譯器處理完之後就沒有該Annotation資訊了 */
CLASS, /* 編譯器将Annotation存儲于類對應的.class檔案中。預設行為 */
RUNTIME /* 編譯器将Annotation存儲于class檔案中,并且可由JVM讀入 */
}
@Documented
- 标記這些注解是否包含在使用者文檔中。
@Inherited
- 标記這個注解是繼承于哪個注解類(預設 注解并沒有繼承于任何子類)
(2)自定義注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Test{
// 注解的參數
String value();
String name() default "預設值"; // default 代表預設值
}
(3)注解與反射
package test1;
import java.lang.annotation.*;
/**
* 模拟資料庫
*/
public class ReflectiveAnnotation {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class class1 = Class.forName("test1.Student");
// 擷取類注解
Annotation[] annotations = class1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation); // @test1.Table(value=db.student)
}
// 擷取類注解的值
Table table = (Table) class1.getAnnotation(Table.class);
String value = table.value();
System.out.println(value); // db.student
// 擷取屬性注解
java.lang.reflect.Field name = class1.getDeclaredField("name");
Field annotation = name.getAnnotation(Field.class);
String name1 = annotation.name();
String type = annotation.type();
int length = annotation.length();
System.out.println(name1); // name
System.out.println(type); // varchar
System.out.println(length); // 3
}
}
/**
* 實體類
*/
@Table("db.student")
class Student {
@Field(name = "name", type = "varchar", length = 3)
private String name;
@Field(name = "age", type = "int", length = 10)
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
/**
* 類名的注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
/**
* 屬性的注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field {
String name();
String type();
int length();
}