Java反射(Class类)常用方法(附Xmind整理)
一、类加载器
1、Java类加载机制
- 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
- 链接:将java类的二进制代码合并到 jvm的运行状态之中的过程,链接过程又分为3个过程:
- 验证:确保加载的类信息符合jvm规范,没有安全方面的问题。
- 准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段, 这些内存都将在方法区中进行分配。
- 解析:虚拟机常量池内的符号引用替换为直接引用的过程。(比如String s =“aaa”,转化为 s的地址指向“aaa”的地址)
- 初始化:初始化阶段是执行类构造器方法的过程。类构造器方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先初始化其父类的初始化虚拟机会保证一个类的构造器方法在多线程环境中被正确加锁和同步 当访问一个java类的静态域时,只有真正声明这个静态变量的类才会被初始 化。
Java类的生命周期:
2、ClassLoader类加载器
ClassLoader类加载器的作用就是将 .class
文件加载到JVM虚拟机中去。
package com.lydms.test;
public class ClassLoaderDemo {
public static void main(String[] args) throws ClassNotFoundException {
//获取类加载器
ClassLoader classLoader = ClassLoaderDemo.class.getClassLoader();
//常用三种方式加载类
// 使用ClassLoader.loadClass()来加载类,不会执行初始化块
System.out.println("‐‐ClassLoader.loadClass()‐‐");
classLoader.loadClass("com.lydms.test.Test1");
// 使用Class.forName(clssName) 来加载类,默认会执行初始化块
System.out.println("‐‐Class.forName(clssName)‐‐");
Class.forName("com.lydms.test.Test2");
// 使用Class.forName(className, initialize, ClassLoader) 来加载类,并指定ClassLoader,初始化时不执行静态块.
// 参数:类名,是否初始化,类加载器
System.out.println("‐‐Class.forName(className,initialize,ClassLoader)‐‐");
Class.forName("com.lydms.test.Test3", false, classLoader);
}
}
class Test1 {
static {
System.out.println("Test1 静态初始化块");
}
}
class Test2 {
static {
System.out.println("Test2 静态初始化块");
}
}
class Test3 {
static {
System.out.println("Test3 静态初始化块");
}
}
二、获取Class对象的方式
1、Class.forName(“全类名”)
通过指定的字符串路径获取
Class<?> aClass = Class.forName("com.lydms.classes.TestFiled");
2、类名.class
通过类名的属性class获取
Class<ArrayList> arrayListClass = ArrayList.class;
3、对象.getClass()
通过对象的getClass()方法获取
Class<? extends TestFiled> aClass = new TestFiled().getClass();
三、常用方法:
字节码文件 | Class类 | Class.forName() |
---|---|---|
构造方法 | Constructor类 | getConstructor() |
成员方法 | Method类 | getMethod() |
成员变量 | Field类 | getField() |
首先获取该类的class对象
Class<?> aClass = Class.forName("com.lydms.classes.TestFiled");
1、获取构造方法、成员方法、成员变量(公开的public)
// 构造方法
Constructor<?>[] constructors = aClass.getConstructors();
// 成员方法
Method[] methods = aClass.getMethods();
// 成员变量
Field[] fields = aClass.getFields();
2、获取构造方法、成员方法、成员变量(所有的public+private)
// 构造方法
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
// 成员方法
Method[] declaredMethods = aClass.getDeclaredMethods();
// 成员变量
Field[] declaredFields = aClass.getDeclaredFields();
3、获取名称
String name = aClass.getName();
// 返回源代码中给出的底层类的简称。
String simpleName = aClass.getSimpleName();
String typeName = aClass.getTypeName();
4、获取父接口
Class<?> superclass = aClass.getSuperclass();
5、获取实现的接口
Class<?>[] interfaces = aClass.getInterfaces();
6、实例化为新对象
Object newInstance = aClass.newInstance();
7、返回此元素上存在的所有注释
返回此元素上存在的所有注释(public)
RestController annotation = aClass.getAnnotation(RestController.class);
// 获取所有
Annotation[] annotations = aClass.getAnnotations();
for (int i = 0; i < annotations.length; i++) {
System.out.println(annotations[i].toString());
}
返回此元素上存在的所有注释(public+private)
RestController declaredAnnotation = aClass.getDeclaredAnnotation(RestController.class);
// 获取所有
Annotation[] aas = aClass.getDeclaredAnnotations();
for (int i = 0; i < aas.length; i++) {
System.out.println(aas[i].toString());
}
8、返回此类的包(package com.lydms.classes)
String packUrl = aClass.getPackage().toString();
9、查找带有给定名称的资源(打印绝对路径)
URL resource = aClass.getResource("TestFiled.class");
System.out.println(resource.getPath().toString());
10、判断类型
// 是否为数组类
boolean isArray = aClass.isArray();
// 是否为接口类
boolean isInterface = aClass.isInterface();
// 是否为枚举类
boolean isEnum = aClass.isEnum();
四、案例
1、获取对应的名称
getName();
通过一个对象获得完整的包名+类名(java.util.HashMap)
HashMap<String, String> hashMap = new HashMap<>();
String name = hashMap.getClass().getName();
System.out.println(name);
2、获得类的简称(HashMap)
getSimpleName();
获得类的简称(HashMap)
HashMap<String, String> hashMap = new HashMap<>();
String typeName = hashMap.getClass().getSimpleName();
System.out.println(typeName);
3.实例化Class对象
forName("com.lydms.utils.Test")
package com.lydms.utils;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 实例化Class对象(com.lydms.utils.Test)
Class<?> aClass1 = Class.forName("com.lydms.utils.Test");
Class<? extends Test> aClass2 = new Test().getClass();
Class<Test> aClass3 = Test.class;
System.out.println(aClass1.getName());
System.out.println(aClass2.getName());
System.out.println(aClass3.getName());
}
}
4、获取一个对象的父接口和实现的接口
getSuperclass(); //父接口
getInterfaces(); //接口实现类
package com.lydms.utils;
import java.io.Serializable;
public class Test implements Serializable {
public static void main(String[] args) throws ClassNotFoundException {
// 4、获取一个对象的父接口和实现的接口
Class<?> aClass = Class.forName("com.lydms.utils.Test");
Class<?> superclass = aClass.getSuperclass();
// 获取到的父类
String parentName = superclass.getName();
System.out.println("父类名为:" + parentName);
// 获得所有的接口实现类
Class<?>[] interfaces = aClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
System.out.println("实现的接口为:" + interfaces[i]);
}
}
}
5、反射机制实例化一个类的对象
newInstance();
getConstructors();
getParameterTypes();
方法一:
// 1、强转为指定格式对象
Class<?> aClass = Class.forName("com.lydms.utils.User");
User user = (User) aClass.newInstance();
user.setName("张三");
user.setAge(11);
System.out.println(user.toString());
方法二:
// 2、方式二(先获取方法对象,在取参数)
Constructor<?>[] constructors = aClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
Class<?>[] parameterTypes = constructors[i].getParameterTypes();
for (int i1 = 0; i1 < parameterTypes.length; i1++) {
String name = parameterTypes[i1].getName();
System.out.println("name"+name);
}
}
实体类
package com.lydms.utils;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
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 "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
6、获取某个类的全部属性
aClass.getDeclaredFields(); //获取本类的全部属性(数组)
aClass1.getFields(); //获取实现的接口或父类的属性
fields[i].getModifiers() //数字型权限修饰符
Modifier.toString(modifiers); //将返回的数字型修饰符,转为string类型。(private static final)
获取本类的全部属性(数组)
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test{
private static final long seriaVersionUID = 342342342;
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.utils.Test");
// 获取本类的全部属性(循环获取)
Field[] fields = aClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
// 权限修饰符(private static final)
int modifiers = fields[i].getModifiers();
String str = Modifier.toString(modifiers);
System.out.println(str);
// 属性类型(long)
Class<?> type = fields[i].getType();
// private static final + long + seriaVersionUID;
System.out.println(str + "+" + type.getName() + "+" + fields[i].getName() + ";");
}
}
获取实现的接口或父类的属性
public interface interfaceTest {
static final long interfaceTest= 111111;
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test implements interfaceTest {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.utils.Test");
Field[] fields1 = aClass.getFields();
for (int i = 0; i < fields1.length; i++) {
int mo = fields1[i].getModifiers();
String str = Modifier.toString(mo);
// 权限修饰符(private static final)
System.out.println(str);
// 属性类型(long)
Class<?> type = fields1[i].getType();
System.out.println(type.getName());
// 方法的名称(interfaceTest)
System.out.println(fields1[i].getName());
}
}
}
7、获取某个类的全部属性(修饰符,入参,返回值)
aClass.getMethods(); //获取类中所有方法
methods[i].getName() //方法名
methods[i].getModifiers(); //修饰符
methods[i].getReturnType().getTypeName(); //返回值类型
methods[i].getParameterTypes(); //获取入参的对象
methods[i].getExceptionTypes() //抛出的异常
待获取方法
package com.lydms.classes;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestClass {
public String getClass(String in) throws IOException {
System.out.println("获取所有的方法");
return null;
}
}
获取TestClass中全部属性
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.classes.TestClass");
Method[] methods = aClass.getMethods();
for (int i = 0; i < methods.length; i++) {
1.方法名(getClass)
String name = methods[i].getName();
2.修饰符(public)
int modifiers = methods[i].getModifiers();
String modifierName = Modifier.toString(modifiers);
3.返回值类型(java.lang.String)
String name1 = methods[i].getReturnType().getName();
4.入参的对象(class java.lang.String)
Class<?>[] parameterTypes = methods[i].getParameterTypes();
5. 抛出的异常( class java.io.IOException)
Class<?>[] exceptionTypes = methods[i].getExceptionTypes();
}
}
8、通过反射机制调用某个类的方法
aClass.newInstance() //闯将TestRun类的对象
test01.invoke(aClass.newInstance()); //执行test01方法
待获取方法
public class TestRun {
public void test01(){
System.out.println("执行Test01方法");
}
public void test02(int age,String name){
System.out.println("执行Test02方法,其中年龄:"+age+",姓名:"+name);
}
}
执行里面方法
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("com.lydms.classes.TestRun");
// 1、调用TestRun类中的test01()方法
Method test01 = aClass.getMethod("test01");
test01.invoke(aClass.newInstance());
// 2、调用TestRun类中的test02()方法
Method test02 = aClass.getMethod("test02", int.class, String.class);
// test02的执行,需要TestRun的对象,和2个入参
test02.invoke(aClass.newInstance(),10,"李四");
}
9、更改类中属性
aClass.getDeclaredField("pro"); //获取里面参数pro的对象
pro.set(testObject, "新的参数"); //设置pro参数的值
pro.get(testObject) //获取pro参数的值(TestFiled类对象)
待获取方法
public class TestFiled {
private String pro = null;
}
执行里面方法
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.classes.TestFiled");
Field pro = aClass.getDeclaredField("pro");
// true 则指示反射的对象在使用时,应该取消Java 语言访问检查
pro.setAccessible(true);
Object testObject = aClass.newInstance();
pro.set(testObject, "新的参数");
/ 打印更改后的参数值
System.out.println(pro.get(testObject));
}
10、执行配置文件中指定的类中方法
配置文件application.properties
className=com.lydms.utils.TestClass
methodName=test
测试执行的方式:
package com.lydms.utils;
public class TestClass {
public void test(){
System.out.println("通过反射执行test中方法");
}
}
反射使用代码:
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class GoToClass {
public static void main(String[] args) throws Exception {
// 1.1 创建Properties对象
Properties pro = new Properties();
// 1.2 加载配置文件,转换为一个集合
InputStream is = new FileInputStream("E:\Code\test\src\main\java\com\lydms\utils\TestClass.java");
// 加载配置信息
pro.load(is);
// 2. 获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 3. 加载该类进内存
Class cls = Class.forName(className);
// 4. 创建对象
Object obj = cls.newInstance();
// 5. 获取方法对象
Method method = cls.getMethod(methodName);
// 6. 执行方法
method.invoke(obj);
}
}
执行结果:
11、通过反射机制往List中添加任意类型的元素
注意:这只是演示反射机制,在正常的开发中不能这样使用(忽略了创建对象时,指定的类型)
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
List<Integer> list = new ArrayList<Integer>();
list.add(11);
//获取类
Class<?> class1 = list.getClass();
//获取方法
Method addMethod = class1.getMethod("add", Object.class);
//执行,添加任意类型对象
addMethod.invoke(list, "asfdgh");
addMethod.invoke(list, true);
addMethod.invoke(list, new Date());
System.out.println(list);
}
}
12、更改方法上注解值
代码(更改board
方法中@RequestMapping
注解的值)
@RestController
@RequestMapping("/test")
public class BoardController {
@RequestMapping(value = "/board", method = {RequestMethod.POST})
public ApiResult board(@RequestBody Map<String, Object> params) throws Exception {
return ApiResult.succ(null);
}
}
获取方式
// 获取成员方法的class对象
Method board = BoardController.class.getMethod("board", Map.class);
// 获取 Test 上的注解
RequestMapping requestMapping = board.getAnnotation(RequestMapping.class);
// 获取代理处理器
InvocationHandler handler = Proxy.getInvocationHandler(requestMapping);
// 过去私有 memberValues 属性
Field f = handler.getClass().getDeclaredField("memberValues");
f.setAccessible(true);
// 获取实例的属性map
Map<String, Object> memberValues = (Map<String, Object>) f.get(handler);
// 修改属性值
memberValues.put("value", "/url");
五、Xmind整理
CSDN地址:
百度网盘地址:
链接:https://pan.baidu.com/s/1_RKxpkZehV0wSFASdv-LXQ
提取码:czz3