#https://blog.csdn.net/a745233700/article/details/82893076(参考)
一、 基本概念
通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写
代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递
的参数来决定,该机制叫做动态编程技术,也就是反射机制。
通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制。
目前主流的框架底层都是采用反射机制实现的。
如:
Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象
p.show(); - 表示调用Person类中的成员方法show
二、 Class类
(1) 基本概念
- java.lang.Class类的实例可以用于描述Java应用程序中的类和接口,也就是一种数据类型。
- 该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内
-
(2) 获取Class对象的方式
使用数据类型.class的方式可以获取对应类型的Class对象(掌握)。
- 使用引用/对象.getClass()的方式可以获取对应类型的Class对象。
- 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象。
- 使用Class.forName()的方式来获取参数指定类型的Class对象(掌握)。
- 使用类加载器ClassLoader的方式获取指定类型的Class对象。
(3) 常用的方法(掌握)
(4)创建对象的两种方式
原始创建~
反射创建~
注意:newInstance的方法已经过时了,所以在通过Constuctor去实例化对象(在“三”中有讲解) ```java package task20;
import java.io.*; import java.util.Scanner; import java.util.UUID;
public class ClassTest { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException { //1,使用原始方式实例化对象 Person p1=new Person(); System.out.println(“无参创建的方式是:”+p1); //0 null //2,使用反射的方式实例化对象,此时是直接给定了一个类类型 Class<?> c1=Class.forName(“task20.Person”); c1.newInstance(); System.out.println(“反射方式实例化对象:”+c1.newInstance());
//也可以通过键盘输入
Scanner sc=new Scanner(System.in);
String str1=sc.next();
Class<?> c2=Class.forName(str1);
System.out.println("从键盘输入的对象实例化:"+c2);
//由此我们也可以知道,还能从配置文件中读取输入
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
String str=br.readLine();
Class<?> c3=Class.forName(str);
System.out.println("从配置文件中读取的对象实例化"+c3.newInstance());
br.close();
}
}
<a name="j7chh"></a>
# ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22605889/1633103015026-f2b74de6-ad2e-47eb-aa0f-e29be7cc9427.png#clientId=u7af1f6bd-c886-4&from=paste&height=187&id=u4073c1e4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=249&originWidth=1400&originalType=binary&ratio=1&size=280213&status=done&style=none&taskId=u4ac0c3b6-ab15-448a-81fa-02286bce28a&width=1050)
<a name="UxyVD"></a>
# 三、Constructor类
<a name="lRG3b"></a>
## (1)基本概念
- java.lang.reflflect.Constructor类主要用于描述获取到的构造方法信息
<a name="ioJsu"></a>
## (2)Class类的常用方法
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22605889/1633097974065-6f40b513-9d1d-4906-9eb0-ff5ea8269276.png#clientId=ub6b268e3-f938-4&from=paste&height=188&id=u34591132&margin=%5Bobject%20Object%5D&name=image.png&originHeight=251&originWidth=1025&originalType=binary&ratio=1&size=61101&status=done&style=none&taskId=u4beb7edf-fc48-4438-b1ca-c525c47b556&width=769)
<a name="VPEtD"></a>
## (3)使用Constructor无参构造实例化对象
```java
package task20;
import java.io.*;
import java.lang.reflect.Constructor;
import java.util.Scanner;
import java.util.UUID;
public class ClassTest {
public static void main(String[] args) throws Exception {
//1,使用原始方式实例化对象
Person p1=new Person();
System.out.println("无参创建的方式是:"+p1); //0 null
//2,使用反射的方式实例化对象,此时是直接给定了一个类类型
Class<?> c1=Class.forName("task20.Person");
//c1.newInstance();
//System.out.println("反射方式实例化对象:"+c1.newInstance());
Constructor<?> constructor = c1.getConstructor();
System.out.println("无参方式创建的对象:"+constructor.newInstance());
/* //也可以通过键盘输入
Scanner sc=new Scanner(System.in);
String str1=sc.next();
Class<?> c2=Class.forName(str1);
System.out.println("从键盘输入的对象实例化:"+c2);
//由此我们也可以知道,还能从配置文件中读取输入
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt")));
String str=br.readLine();
Class<?> c3=Class.forName(str);
System.out.println("从配置文件中读取的对象实例化"+c3.newInstance());*/
}
}
(4)使用有参构造方法实例化对象
(5)Constructor类的常用方法
(5)获取类中的所有构造方法的参数信息
Constructor<?>[] constructors = c1.getConstructors();
for (Constructor ct:constructors
) {
System.out.println("构造方法的访问修饰符是:"+ct.getModifiers());
System.out.println("构造方法的名称为:"+ct.getName());
System.out.println("参数类型是:");
Class[] parameterTypes = ct.getParameterTypes();
for (Class ps:parameterTypes
) {
System.out.println(ps);
}
}
四、Field类
(1)基本概念
java.lang.reflflect.Field类主要用于描述获取到的单个成员变量信息
(2) Class类的常用方法
(3)Field类的常用方法
(4)获取成员变量数值的两种方式
package task20;
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(10,"林三");
System.out.println(p1.getName());
//1-2如果name为public修饰的,可以直接p1.name访问
System.out.println("---------------------------");
//2 使用反射机制制造对象,并获取成员变量的数据并打印
//2.1 获取Class对象
Class<?> aClass = Class.forName("task20.Person");
//2.2 根据Clss对象获取(有参)Constructor构造方法
Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
//2.3 使用有参构造方法得到Person类型的对象
Object object = constructor.newInstance(10, "王五");
//2.4 根据Class对象获取对应的成员变量信息 name为成员字段的名字
Field name1 = aClass.getDeclaredField("name");
//2.5 使用person类型的对象获取成员变量的数值并打印 获取对应字段的值
System.out.println("获取到的成员变量信息为:"+name1.get(object));
}
}
(5)修改成员变量数值的两种方式
package task20;
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(10,"林三");
System.out.println(p1.getName());
//1-2如果name为public修饰的,可以直接p1.name访问
System.out.println("---------------------------");
//2 使用反射机制制造对象,并获取成员变量的数据并打印
//2.1 获取Class对象
Class<?> aClass = Class.forName("task20.Person");
//2.2 根据Clss对象获取(有参)Constructor构造方法
Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
//2.3 使用有参构造方法得到Person类型的对象
Object object = constructor.newInstance(10, "王五");
//2.4 根据Class对象获取对应的成员变量信息 name为成员字段的名字
Field field = aClass.getDeclaredField("name");
//设置java语言访问检查
//field.setAccessible(true);
//2.5 使用person类型的对象获取成员变量的数值并打印 获取对应字段的值
System.out.println("获取到的成员变量信息为:"+field.get(object));
System.out.println("--------------------------------");
//3,修改成员变量的值
//使用原始方式去进行修改
// p1.name="张三";
//System.out.println("通过原始方式修改后的值为"+p1.name);
//4,使用反射机制修改指定对象成员变量中的值
//修改object对象中的成员变量名为field的数值为关羽,即修改Person中name的值为关羽
field.set(object,"关羽");
System.out.println("通过反射修改的值为"+field.get(object));
}
}
如果访问的成员变量的修饰符为public,则直接访问和通过反射访问都没问题
如果访问的成员变量的修饰符为private,则不能直接访问,通过反射机制进行访问时,要进行java语言访问检查设置,这个也称为暴力反射。
package task20;
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(10,"林三");
System.out.println(p1.getName());
//1-2如果name为public修饰的,可以直接p1.name访问
System.out.println("---------------------------");
//2 使用反射机制制造对象,并获取成员变量的数据并打印
//2.1 获取Class对象
Class<?> aClass = Class.forName("task20.Person");
//2.2 根据Clss对象获取(有参)Constructor构造方法
Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
//2.3 使用有参构造方法得到Person类型的对象
Object object = constructor.newInstance(10, "王五");
//2.4 根据Class对象获取对应的成员变量信息 name为成员字段的名字
Field field = aClass.getDeclaredField("name");
//设置java语言访问检查
field.setAccessible(true); /*** 设置!!!***/
//2.5 使用person类型的对象获取成员变量的数值并打印 获取对应字段的值
System.out.println("获取到的成员变量信息为:"+field.get(object));
System.out.println("--------------------------------");
//3,修改成员变量的值
//使用原始方式去进行修改
// p1.name="张三";
//System.out.println("通过原始方式修改后的值为"+p1.name);
//4,使用反射机制修改指定对象成员变量中的值
//修改object对象中的成员变量名为field的数值为关羽,即修改Person中name的值为关羽
field.set(object,"关羽");
System.out.println("通过反射修改的值为"+field.get(object));
}
}
(6)获取所有成员变量的实现
//5,获取所有成员变量
Field[] declaredFields = aClass.getDeclaredFields();
for (Field ds:declaredFields
) {
System.out.println("获取到的成员变量的修饰符为"+ds.getModifiers());
System.out.println("获取到的成员变量的类型为"+ds.getType());
System.out.println("获取到的成员变量名称为"+ds.getName());
System.out.println("---------------------------------------");
}
五、Method类
(1)基本概念
java.lang.reflflect.Method类主要用于描述获取到的单个成员方法信息。
(2)Class类的常用方法
(3)Method类的常用方法
(4)获取成员方法的方式
//6,使用反射机制制造对象,并调用方法打印结果
// 6.1 使用Class类制造对象
Class<?> aClass1 = Class.forName("task20.Person");
// 6.2 使用Constructor方法获取有参构造方法
Constructor<?> constructor1 = aClass1.getConstructor(int.class, String.class);
// 6.3 使用有参的构造方法制造对象
Object object2 = constructor1.newInstance(20, "好家伙");
// 6.4 根据Class对象获取对象的成员方法
Method method=aClass1.getMethod("getName");
// 6.5 使用对象调用成员方法并打印 相当于调用object2的getName()方法
System.out.println("调用方法的返回是:"+method.invoke(object2));
(5)获取所有成员方法的实现
package com.lagou.task20;
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("zhangfei", 30);
System.out.println("调用方法的返回值是:" + p1.getName()); // zhangfei
System.out.println("------------------------------------------------------");
// 2.使用反射机制构造对象并调用方法打印结果
// 2.1 获取Class对象
Class c1 = Class.forName("com.lagou.task20.Person");
// 2.2 根据Class对象来获取对应的有参构造方法
Constructor constructor = c1.getConstructor(String.class, int.class);
// 2.3 使用有参构造方法构造对象并记录
Object object = constructor.newInstance("zhangfei", 30);
// 2.4 根据Class对象来获取对应的成员方法
Method method = c1.getMethod("getName");
// 2.5 使用对象调用成员方法进行打印
// 表示使用object对象调用method表示的方法,也就是调用getName方法来获取姓名
System.out.println("调用方法的返回值是:" + method.invoke(object)); // zhangfei
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 com.lagou.task20;
import java.io.Serializable;
@MyAnnotation
public class Student<T, E> extends Person implements Comparable, Serializable {
@Override
public int compareTo(Object o) {
return 0;
}
}
package com.lagou.task20;
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.task20.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();
}
}