携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
1. 反射
1.1. 反射介绍
1.1.1. 什么是反射?
Reflection(反射)是java被视为动态语言的关键,反射机制允许程序在执行期借助与Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
1.1.2. 反射优点和缺点
优点: 可以实现动态创建对象和编译,体现出很大的灵活性
缺点: 让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。
我们先定义一个TargetObject给我们操作:
public class TargetObject {
private String value;
public TargetObject() {
value = "JavaGuide";
}
public void publicMethod(String s) {
System.out.println("I love " + s);
}
private void privateMethod() {
System.out.println("value is " + value);
}
}
1.2. 获取 Class 对象的四种方式
1. 知道具体类的情况下可以使用:
Class<TargetObject> targetObjectClass = TargetObject.class;
String name = targetObjectClass.getName();
System.out.println(name);
// 结果:
// com.he.interview.pojo.TargetObject
但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象,通过此方式获取 Class 对象不会进行初始化
2. 通过 Class.forName()传入类的全路径获取:
Class targetObject = Class.forName("com.he.interview.pojo.TargetObject");
System.out.println(targetObject);
// 结果:
// class com.he.interview.pojo.TargetObject
3. 通过对象实例instance.getClass()获取:
TargetObject o = new TargetObject();
Class alunbarClass2 = o.getClass();
4. 通过类加载器xxxClassLoader.loadClass()传入类路径获取:
Class targetObject4Class = ClassLoader.getSystemClassLoader().loadClass("com.he.interview.pojo.TargetObject");
System.out.println(targetObject4Class);
// 结果:
// class com.he.interview.pojo.TargetObject
通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行
示例:
public class 获取Class对象的四种方式 {
public static void main(String[] args) throws ClassNotFoundException {
// 1. 知道具体类的情况下可以使用
Class<TargetObject> targetObjectClass = TargetObject.class;
String name = targetObjectClass.getName();
System.out.println(name);
// 2. 通过 Class.forName()传入类的全路径获取:
Class targetObject = Class.forName("com.he.interview.pojo.TargetObject");
System.out.println(targetObject);
// 3. 通过对象实例instance.getClass()获取:
TargetObject targetObject3 = new TargetObject();
Class<? extends TargetObject> targetObject3Class = targetObject3.getClass();
// 4. 通过类加载器xxxClassLoader.loadClass()传入类路径获取:
Class targetObject4Class = ClassLoader.getSystemClassLoader().loadClass("com.he.interview.pojo.TargetObject");
System.out.println(targetObject4Class);
}
}
1.3. 哪些类型可以有Class对象
- class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
- interface:接口
- []: 数组
- enum: 枚举
- annotation:注解@interface
- primtitve Type:基本数据类型
- void:返回值
package com.he.interview.reflection;
import java.lang.annotation.ElementType;
public class 哪些类型可以有Class对象 {
public static void main(String[] args) {
Class c1 = Object.class; //类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; //一维数组
Class c4 = int[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class;//enum枚举
Class c7 = Integer.class; //基本类型
Class c8 = void.class; //返回值类型
System.out.println("类" + c1);
System.out.println("接口" + c2);
System.out.println("一维数组" + c3);
System.out.println("二维数组" + c4);
System.out.println("注解" + c5);
System.out.println("enum枚举" + c6);
System.out.println("基本类型" + c7);
System.out.println("返回值类型" + c8);
//只要元素类型与维度一样,就是同一个class对象
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
输出结果:
类class java.lang.Object
接口interface java.lang.Comparable
一维数组class [Ljava.lang.String;
二维数组class [[I
注解interface java.lang.Override
enum枚举class java.lang.annotation.ElementType
基本类型class java.lang.Integer
返回值类型void
1163157884
1163157884
1.4. 使用反射操作这个类的方法以及参数
public class 使用反射操作这个类的方法以及参数 {
public static void main(String[] args) throws Exception {
// 获取 TargetClass 类的 Class 对象并且创建 TargetClass类实例
Class<?> targetClass = Class.forName("com.he.interview.pojo.TargetObject");
TargetObject targetObject = (TargetObject) targetClass.newInstance();
// 获取 TargetObject类定义的所有方法(包括private等)
Method[] declaredMethods = targetClass.getDeclaredMethods();
System.out.println("获得的类的方法有:");
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
// 获得指定方法并调用
Method publicMethod = targetClass.getDeclaredMethod("publicMethod", String.class);
publicMethod.invoke(targetObject, "正在调用"); // 第一个参数是类的实例对象
// 获取类的指定参数并进行修改
Field field = targetClass.getDeclaredField("value");
System.out.println("输出获取类的指定参数:" + field);
//为了对类中的参数进行修改我们取消安全检查
field.setAccessible(true);
field.set(targetObject, "heriec");
System.out.println("指定参数的值为:" + field.get(targetObject));
// 调用 private 方法
Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
// 为调用 private方法我们取消安全检查
privateMethod.setAccessible(true);
privateMethod.invoke(targetObject);
}
}
输出结果:
获得的类的方法有:
publicMethod
privateMethod
正在调用publicMethod方法
输出获取类的指定参数:private java.lang.String com.he.interview.pojo.TargetObject.value
指定参数的值为:heriec
value is heriec