學習筆記輸出來源:拉勾教育Java就業急訓營
修改時間:2021年1月8日
作者:pp_x
郵箱:[email protected]
文章目錄
- 反射機制
-
- 基本概念
- Class類
-
- 基本概念
- 擷取Class對象方式
- 常用方法
- Constructor類
-
- 基本概念
- Class常用方法
- Constructor類常用的方法
- Field類
-
- 基本概念
- Class的常用方法
- Field常用方法
- Method類
-
- 基本概念
- Class類的常用方法
- Method類的常用方法
- 擷取其他結構資訊
反射機制
基本概念
- 通常情況下編寫代碼都是固定的,無論運作多少次執行的結果也是固定的,在某些特殊場合中編寫代碼時不确定要建立什麼類型的對象,也不确定要調用什麼樣的方法,這些都希望通過運作時傳遞的參數來決定,該機制叫做動态程式設計技術,也就是反射機制。
- 通俗來說,反射機制就是用于動态建立對象并且動态調用方法的機制。
- 目前主流的架構底層都是采用反射機制實作的。
Class類
基本概念
-
類的執行個體可以用于描述Java應用程式中的類和接口,也就是一種資料類型java.lang.Class
- 該類沒有公共構造方法,該類的執行個體由Java虛拟機和類加載器自動構造完成,本質上就是加載到記憶體中的運作時類。
擷取Class對象方式
- 使用
的方式擷取對應類型的Class對象資料類型.class
- 使用
方式擷取對應類型的Class對象對象/引用.getClass()
- 使用
的方式可以擷取基本資料類型的Class對象包裝類.TYPE
- 使用使用
的方式來擷取參數指定類型的Class對象Class.forName()
- 使用類加載器
的方式擷取指定類型的Class對象。ClassLoader
常用方法
方法聲明 | 功能 |
---|---|
static Class<?> forName(String className) | 用于擷取參數指定類型對應的Class對象并傳回 |
T newInstance() | 用于建立該Class對象所表示類的新執行個體 |
package com.lagou.classtest;
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
// 1.使用資料類型.class的方式可以擷取對應類型的Class對象
Class c1 = String.class;
System.out.println("c1 = " + c1); // 自動調用toString方法 class java.lang.String
c1 = int.class;
System.out.println("c1 = " + c1); // int
c1 = void.class;
System.out.println("c1 = " + c1); // void
System.out.println("---------------------------------------------------");
// 2.使用對象.getClass()的方式擷取對應的Class對象
String str1 = new String("hello");
c1 = str1.getClass();
System.out.println("c1 = " + c1); // class java.lang.String
Integer it1 = 20;
c1 = it1.getClass();
System.out.println("c1 = " + c1); // class java.lang.Integer
int num = 5;
//num.getClass(); Error: 基本資料類型的變量不能調用方法
System.out.println("---------------------------------------------------");
// 3.使用包裝類.TYPE的方式來擷取對應基本資料類型的Class對象
c1 = Integer.TYPE;
System.out.println("c1 = " + c1); // int
c1 = Integer.class;
System.out.println("c1 = " + c1); // class java.lang.Integer
System.out.println("---------------------------------------------------");
// 4.調用Class類中的forName方法來擷取對應的Class對象
//c1 = Class.forName("String"); // Error 要求寫完整的名稱:包名.類名
c1 = Class.forName("java.lang.String");
System.out.println("c1 = " + c1); // class java.lang.String
c1 = Class.forName("java.util.Date");
System.out.println("c1 = " + c1); // class java.util.Date
//c1 = Class.forName("int");
//System.out.println("c1 = " + c1); // 不能擷取基本資料類型的Class對象
System.out.println("---------------------------------------------------");
// 5.使用類加載器的方式來擷取Class對象
ClassLoader classLoader = ClassTest.class.getClassLoader();
System.out.println("classLoader = " + classLoader); // null
c1 = classLoader.loadClass("java.lang.String");
System.out.println("c1 = " + c1); // class java.lang.String
}
}
Constructor類
基本概念
-
類主要用于描述擷取到的構造方法資訊java.lang.reflect.Constructor
Class常用方法
方法聲明 | 功能 |
---|---|
Constructor getConstructor(Class<?>… parameterTypes) | 用于擷取此Class對象所表示類型中參數指定的公共構造方法 |
Constructor<?>[] getConstructors() | 用于擷取此Class對象所表示類型中所有的公共構造方法 |
Constructor類常用的方法
方法聲明 | 功能 |
---|---|
T newInstance(Object… initargs) | 使用此Constructor對象描述的構造方法來構造Class對象代表類型的新執行個體 |
int getModifiers() | 擷取方法的通路修飾符 |
String getName() | 擷取方法的名稱 |
Class<?>[] getParameterTypes() | 擷取方法所有參數的類型 |
package com.lagou.classtest;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Scanner;
public class PersonConstructorTest {
public static void main(String[] args) throws Exception {
// 1、使用原始形式以無參構造形式構造Person的對象
System.out.println("----------------使用原始形式以無參構造形式構造Person的對象--------------");
Person p1 = new Person();
System.out.println(p1.toString());
// 2、使用反射機制以無參形式構造Person的對象
System.out.println("----------------------使用反射機制以無參形式構造Person的對象---------------");
// 建立對象的類型可以從鍵盤輸入
// System.out.println("請輸入要建立對象的類型:");
// Scanner sc = new Scanner(System.in);
// String str1 = sc.next();
// Class c1 = Class.forName("com.lagou.classtest.Person");
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
String str1 = br.readLine();
Class c1 = Class.forName(str1);
//System.out.println("無參方式建立的對象是:" + c1.newInstance()); // null 0
// 擷取Class對象對應類中的無參構造方法,也就是Person類中的無參構造方法
Constructor constructor = c1.getConstructor();
// 使用擷取到的無參構造方法來構造對應類型的對象,也就是Person類型的對象
System.out.println("無參方式建立的對象是:" + constructor.newInstance());
br.close();
//3、
System.out.println("--------------------使用原始方式以有參方式構造Person類型的對象并列印-------------------------------");
// 3.使用原始方式以有參方式構造Person類型的對象并列印
Person p2 = new Person("liuxiao", 18);
System.out.println("有參方式構造的對象是:" + p2); // zhangfei 30
System.out.println("---------------------4.使用反射機制以有參方式構造Person類型的對象并列印------------------------------");
// 4.使用反射機制以有參方式構造Person類型的對象并列印
// 擷取Class對象對應類中的有參構造方法,也就是Person類中的有參構造方法
Constructor constructor1 = c1.getConstructor(String.class, int.class);
// 使用擷取到的有參構造方法來構造對應類型的對象,也就是Person類型的對象
// newInstance方法中的實參是用于給有參構造方法的形參進行初始化的,也就是給name和age進行初始化的
System.out.println("有參方式構造的對象是:" + constructor1.newInstance("zhangfei", 30)); // zhangfei 30
System.out.println("--------------------// 5.使用反射機制擷取Person類中所有的公共構造方法并列印-------------------------------");
5.使用反射機制擷取Person類中所有的公共構造方法并列印
Constructor[] constructors = c1.getConstructors();
for (Constructor ct: constructors
) {
System.out.println("構造方法的通路修飾符是:"+ct.getModifiers());
System.out.println("構造方法的名稱是:"+ct.getName());
Class[] parameterTypes = ct.getParameterTypes();
for (Class c:parameterTypes
) {
System.out.print(c +", ");
}
System.out.println();
}
}
}
Field類
基本概念
-
類主要用于描述擷取到的單個成員變量java.lang.reflect.Field
Class的常用方法
方法聲明 | 功能 |
---|---|
Field getDeclaredField(String name) | 用于擷取此Class對象所表示類中參數指定的單個成員變量資訊 |
Field[] getDeclaredFields() | 用于擷取此Class對象所表示類中所有成員變量資訊 |
Field常用方法
方法聲明 | 功能 |
---|---|
Object get(Object obj) | 擷取對象obj中此Field類所代表的成員變量的數值 |
void set(Object obj, Object value) | 修改對象obj中此Field類中所代表成員變量的數值為value |
void setAccessible(boolean flag) | 當flag為true時,反射對象在使用時 應該取消Java語言通路檢查 |
int getModifiers() | 擷取成員變量的通路修飾符 |
Class<?> getType() | 擷取成員變量的資料類型 |
String getName() | 擷取成員變量的名稱 |
package com.lagou.classtest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class PersonFieldTest {
public static void main(String[] args) throws Exception {
// 1.使用原始方式來構造對象以及擷取成員變量的數值并列印
Person p1 = new Person("zhangfei", 30);
//System.out.println("擷取到的成員變量數值為:" + p1.name); // zhangfei
System.out.println("-------------------------------------------------------");
// 2.使用反射機制來構造對象以及擷取成員變量的數值并列印
// 2.1 擷取Class對象
Class c1 = Class.forName("com.lagou.classtest.Person");
// 2.2 根據Class對象擷取對應的有參構造方法
Constructor constructor = c1.getConstructor(String.class, int.class);
// 2.3 使用有參構造方法來得到Person類型的對象
Object object = constructor.newInstance("zhangfei", 30);
// 2.4 根據Class對象擷取對應的成員變量資訊
Field field = c1.getDeclaredField("name");
// 設定Java語言通路檢查的取消 暴力反射
field.setAccessible(true);
// 2.5 使用Person類型的對象來擷取成員變量的數值并列印
// 擷取對象object中名字為field成員變量的數值,也就是成員變量name的數值
System.out.println("擷取到的成員變量數值為:" + field.get(object)); // zhangfei
System.out.println("-------------------------------------------------------");
// 3.使用原始方式修改指定對象中成員變量的數值後再次列印
//p1.name = "guanyu";
//System.out.println("修改後成員變量的數值為:" + p1.name); // guanyu
System.out.println("-------------------------------------------------------");
// 4.使用反射機制修改指定對象中成員變量的數值後再次列印
// 表示修改對象object中名字為field成員變量的數值為guanyu,也就是成員變量name的數值為guanyu
field.set(object, "guanyu");
System.out.println("修改後成員變量的數值為:" + field.get(object)); // guanyu
System.out.println("--------------------------擷取Class對象對應類中所有的成員變量-----------------------------");
// 5.擷取Class對象對應類中所有的成員變量
Field[] declaredFields = c1.getDeclaredFields();
for (Field ft : declaredFields) {
System.out.println("擷取到的通路修飾符為:" + ft.getModifiers());
System.out.println("擷取到的資料類型為:" + ft.getType());
System.out.println("擷取到的成員變量名稱是:" + ft.getName());
System.out.println("-----------------");
}
}
}
Method類
基本概念
-
類主要用于描述單個成員方法的資訊java.lang.reflect.Method
Class類的常用方法
方法聲明 | 功能 |
---|---|
Method getMethod(String name, Class<?>… parameterTypes) | 使用者擷取該Class對象表示類中名字為name,參數清單為parameterTypes的成員方法 |
Method[] getMethods() | 用于擷取該Class對象表示類中所有公共成員方法 |
Method類的常用方法
方法聲明 | 功能 |
---|---|
Object invoke(Object obj, Object… args) | 使用obj對象來調用此類表示的方法,args代表方法需要傳遞的實參清單,傳回方法的傳回值 |
int getModifiers() | 擷取方法的通路修飾符 |
Class<?> getReturnType() | 擷取方法的傳回類型 |
String getName() | 擷取方法的名稱 |
Class<?>[] getParameterTypes() | 擷取方法的參數清單 |
Class<?>[] getExceptionTypes() | 擷取方法的異常資訊 |
package com.lagou.classtest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class PersonMethodTest {
public static void main(String[] args) throws Exception{
//1、使用原始方法構造對象并調用方法
Person p1 = new Person("liuxiao",18);
System.out.println("調用方法的傳回值是:"+p1.getName());
System.out.println("--------------");
//使用反射機制
//擷取Class對象
Class c1 = Class.forName("com.lagou.classtest.Person");
//通過Class對象擷取對應的有參構造方法
Constructor constructor = c1.getConstructor(String.class,int.class);
//使用有參構造方法構造對象
Object object = constructor.newInstance("liuxiao",18);
//Object object2 = constructor.newInstance("xiaoliu",19);
//根據Class對象擷取成員方法對象
Method method = c1.getMethod("getName");
//根據成員方法對象調用成員方法進行列印
System.out.println("調用方法的傳回值是:"+method.invoke(object));
System.out.println("------------------------使用反射機制來擷取類中的所有成員方法并列印------------------------------");
// 3.使用反射機制來擷取類中的所有成員方法并列印
Method[] methods = c1.getMethods();
for (Method mt : methods) {
System.out.println("成員方法的修飾符是:" + mt.getModifiers());
System.out.println("成員方法的傳回值類型是:" + mt.getReturnType());
System.out.println("成員方法的名稱是:" + mt.getName());
System.out.println("成員方法形參清單的類型是:");
Class<?>[] parameterTypes = mt.getParameterTypes();
for (Class ct : parameterTypes) {
System.out.print(ct + " ");
}
System.out.println();
System.out.println("成員方法的異常類型清單是:");
Class<?>[] exceptionTypes = mt.getExceptionTypes();
for (Class ct: exceptionTypes) {
System.out.print(ct + " ");
}
System.out.println();
System.out.println("---------------------------------------------------");
}
}
}
擷取其他結構資訊
方法聲明 | 功能 |
---|---|
Package getPackage() | 擷取包資訊 |
Class<? super T> getSuperclass() | 擷取父類資訊 |
Class<?>[] getInterfaces() | 擷取接口資訊 |
Annotation[] getAnnotations() | 擷取注解資訊 |
Type[] getGenericInterfaces() | 擷取檢討資訊 |
package com.lagou.classtest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class StudentTest {
public static void main(String[] args) throws Exception {
// 擷取Student類型的Class對象
Class c1 = Class.forName("com.lagou.classtest.Student");
System.out.println("擷取到的包資訊是:" + c1.getPackage());
System.out.println("擷取到的父類資訊是:" + c1.getSuperclass());
System.out.println("-------------------------------------------------");
System.out.println("擷取到的接口資訊是:");
Class[] interfaces = c1.getInterfaces();
for (Class ct : interfaces) {
System.out.print(ct + " ");
}
System.out.println();
System.out.println("-------------------------------------------------");
System.out.println("擷取到的注解資訊是:");
Annotation[] annotations = c1.getAnnotations();
for (Annotation at : annotations) {
System.out.print(at + " ");
}
System.out.println();
System.out.println("-------------------------------------------------");
System.out.println("擷取到的泛型資訊是:");
Type[] genericInterfaces = c1.getGenericInterfaces();
for (Type tt : genericInterfaces) {
System.out.print(tt + " ");
}
System.out.println();
}
}
執行結果
擷取到的包資訊是:package com.lagou.classtest
擷取到的父類資訊是:class com.lagou.classtest.Person
-------------------------------------------------
擷取到的接口資訊是:
interface java.lang.Comparable interface java.io.Serializable
-------------------------------------------------
擷取到的注解資訊是:
@com.lagou.classtest.MyAnnotation()
-------------------------------------------------
擷取到的泛型資訊是:
interface java.lang.Comparable interface java.io.Serializable