天天看點

【java】反射機制詳解與應用(含注解)一、反射概述二、擷取Class類對象的三種方法三、Class對象功能四、執行個體五、反射與注解

目錄

  • 一、反射概述
  • 二、擷取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)注解與反射

一、反射概述

反射:把類中的各個組成部分映射成一個個的對象(指在程式的運作狀态中,可以構造任意一個類的對象,可以了解任意一個對象所屬的類,可以了解任意一個類的成員變量和方法,可以調用任意一個對象的屬性和方法。)

【java】反射機制詳解與應用(含注解)一、反射概述二、擷取Class類對象的三種方法三、Class對象功能四、執行個體五、反射與注解

二、擷取Class類對象的三種方法

  1. Class.forName(“全類名”)
  2. 類名.class
  3. 對象.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成員變量時卻報錯了

【java】反射機制詳解與應用(含注解)一、反射概述二、擷取Class類對象的三種方法三、Class對象功能四、執行個體五、反射與注解

隻需忽略通路修飾符的安全檢查

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

【java】反射機制詳解與應用(含注解)一、反射概述二、擷取Class類對象的三種方法三、Class對象功能四、執行個體五、反射與注解

代碼示例:

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();
}