From 68b9b34345a6f0d149bdad255429c8f578af04a8 Mon Sep 17 00:00:00 2001 From: rikako <496063163@qq.com> Date: Sun, 7 May 2023 23:44:59 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=85=E8=AF=BB=E5=8F=8D=E5=B0=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java se/反射.md | 187 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 java se/反射.md diff --git a/java se/反射.md b/java se/反射.md new file mode 100644 index 0000000..efe5b7d --- /dev/null +++ b/java se/反射.md @@ -0,0 +1,187 @@ +# 反射 +## Class对象 +Class对象用于访问类信息,想要获取class对象,可以通过如下方法 +### 获取Class对象方法 +#### 调用实例的getClass方法 +```java +Random generator = new Random(): +Class cl = generator . getClass () ; +String name = cl.getName() ; // name is set to "java . util . Random" +``` +#### 调用Class类的静态方法forName方法 +```java +String dassName = " java . util . Random" ; +Class cl = Class.forName ( dassName ) ; +``` + +#### 通过T.class获取 +如果T是一个java类型,那么T.class代表T类型对应的Class对象 +```java +Class dl = Random.class; +Gass cl 2 = int.class ; +Class cl 3 = Double[].class ; +``` +Class对象表示的是一个类型,而类型不一定是类,也包含基本类型,如int,long等。 + +### Class对象的比较 +JVM为每个类型只维护一个Class对象,故而不同的Class之间可以通过`==`符号进行比较 +```java +if(e.getClass()==Employee.class) +``` +### 通过Class对象创建新实例 +下述示例创建了一个与e具有相同类型的实例,newInstance方法默认会调用默认构造函数,如果该类型没有默认构造函数,会抛出一个checked exception +```java +e.getClass().newInstance() +``` +如果将forName和newInstance方法结合起来使用,可以根据存储在字符串中的类型动态创建一个对象: +```java +String driverClassName = "com.mysql.cj.jdbc.Driver"; +Class.forName(driverClassName).newInstance(); +``` + +## 使用反射分析类 +java.lang.reflect类中含有三个类: +- Field:用于描述类的域 +- Method:用于描述类的方法 +- Constructor:用于描述类的构造器 + +### Field.getType +Field类有一个getType方法,返回值是域所属类型的Class对象。 +### 获取类的域、方法和构造器 +#### Class.getFields +返回值为类的public域,包含从父类继承的public域 +#### Class.getDeclaredFields +返回类中声明的所有域,包含为private和protected的域,但是不包含从父类继承的域 +#### Class.getMethods +返回值为类提供的public方法,包含从父类继承的public方法 +#### Class.getDeclaredMethods +返回类中声明的所有方法,包含private方法和protected方法,但是不包含从父类继承的方法 +#### Class.getConstructors +只能获取到public构造器 +#### Class.getDeclaredConstructors +能获取到所有的构造器,包含private和protected构造器 +### Method、Field、Constructor中的方法 +#### getDeclaringClass +返回定义该方法、域、构造器类型的Class对象 +```java +Class getDeclaringClass() +``` +#### getExceptionTypes(Method和Constructor中包含) +返回方法抛出的异常类型的数组 +```java +Class[] getExceptionTypes() +``` +#### getModifiers +返回一个描述Field、Method、Constrcutor的修饰符的整数类型(不同的位描述不同的修饰符状态,如public、static、是否抽象类、是否接口等) +```java +int getModifiers() +``` +#### getName +返回描述Field、Constructor、Method的字符串 +```java +String getName() +``` +#### getParameterTypes(Method和Constructor中包含) +返回一个Class数组,用于描述参数类型 +```java +Class[] getParameterTypes() +``` +#### getReturnType(只在Method方法中包含) +返回Method的返回类型 +```java +Class getReturnType() +``` +### Modifier中的方法 +#### toString +该静态方法将modifiers整数中的修饰符内容转化为字符串 +```java +static String toString(int modifiers) +``` +#### isAbstract +```java +static boolean isAbstract(int modifiers) +``` +#### isFinal +```java +static boolean isFinal(int modifiers) +``` +#### isInterface +```java +static boolean isInterface(int modifiers) +``` +#### isNative +```java +static boolean isNative(int modifiers) +``` +#### isPrivate +```java +static boolean isPrivate(int modifiers) +``` +#### isProtected +```java +static boolean isProtected(int modifiers) +``` +#### isPublic +```java +static boolean isPublic(int modifiers) +``` +#### isStatic +```java +static boolean isStatic(int modifiers) +``` +#### isSynchronized +```java +static boolean isSynchronized(int modifiers) +``` +#### isVolatile +```java +static boolean isVolatile(int modifiers) +``` +## 使用反射分析类的内容 +如果在运行时有一个Field对象和一个类实例obj,想要查看obj实例中Field对应域的值,可以使用如下方式: +```java +f.get(obj); +``` +但是,如果Field的modifiers显示该Field是private的,那么`f.get(obj)`方法将会抛出一个IllegalAccessException。 +此时,可以通过`f.setAccessible(true)`来访问private域中的内容。 +```java +f.setAccessible(true); +Object v = f.get(obj); +``` +设置Field的值则是可以通过`f.set(obj,value)`来实现。 +```java +f.setAccessible(true); +f.setValue(obj,"shiro"); +``` +### AccessibleObject +Field,Method,Constructor类型都拥有公共的父类AccessibleObject +#### setAccessible +```java +void setAccessible(boolean flag); + +// 批量设置可访问状态 +static void setAccessible(AccessibleObject[] array,boolean flag); +``` +#### isAccessible +```java +boolean isAccessible(); +``` +## 使用反射调用方法 +Method类中提供了一个invoke方法来调用Method所表示的方法,`Method.invoke`方法签名如下: +```java +Object invoke(Object obj,Object... args) +``` +obj表示调用方法的对象,args表示参数数组。 +> 如果Method位静态方法,那么obj应该传入null + +如果Method代表的方法返回的是一个基本类型,那么invoke方法会返回器包装类型,如`int->Integer`. +### Method.getMethod +如果想要根据方法名称和参数类型来获取Class对象中的Method,可以调用如下方法: +```java +Method getMethod(String name,Class... parameterTypes) +``` +示例如下: +```java +Method ml = Employee. class.getMethod ( "getName") ; +Method m2 = Employee.class.getMethod ( "raiseSalary" , double.class) ; +``` \ No newline at end of file