介绍
JAVA反射机制是指程序在运行状态时,可以动态获取某个类的成员属性,变量,方法等等。还可以动态的创建类的实例,通过类的对象调用类的方法等等的动态操作。这种动态操作称为Java的反射机制。那么在了解反射机制前需要先了解一下在Java中类是如何加载的。
在Java程序执行的时候,首先jvm会从Java硬盘中读取源文件,并将源文件(.Java文件)读取到方法区中并创建对应且唯一的class文件,也就是上图所示方法区中的类对象。这个class文件中包含着我们创建类的对象时所需要的模板信息,也就是源文件中的属性、方法等等。Class本身也是一个类,它的主要功能之一就是生成类加载时的class文件,为类的初始化及实例化做准备。而我们在程序中通过关键字new创建的对象创建的是类的对象,而不是类对象,二者的区别如图中所示。
反射的基本使用
首先创建一个Student类,里边包含私有属性、构造函数、toString方法。
public class Student {
private String name;
public Integer age;
private void private_show() {
System.out.println("用户名:"+name+",年龄:"+age+"!");
}
public void show() {
System.out.println("用户名:"+name+",年龄:"+age+"!");
}
public Student(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
}
接着我们通过反射机制动态获取类对象(类对象里包含着类的所有模板信息,我们就可以对类进行其他动态操作了)
获取类的三种方式
public class Demo {
//获取类的三种方式
public static void main(String[] args) throws ClassNotFoundException {
//获取方式一
Student stu1 = new Student();
Class stu1Class = stu1.getClass();
System.out.println(stu1Class);
//获取方式二
Class stu2Class = Student.class;
System.out.println(stu2Class);
//获取方式三
Class<?> stuClass = Class.forName("Demo.Student");//包名.类名
System.out.println(stu3Class);
//比较是否相同
System.out.println(stu1Class == stu2Class);
System.out.println(stu1Class == stu3Class);
//结果
// class Demo.Student
// class Demo.Student
// class Demo.Student
// true
// true
}
}
需要注意的是第三种获取方式的参数格式必须是包名.类名,否则JVM无法定位这个类的具体位置。
那么三种方式最常用的是第三种方式。理由如下:
- 第一种:需要创建对象,也就没有使用反射机制的意义了,显得多此一举。
- 第二种:需要导入包,依赖性太强。
- 所以选择第三种。
创建类的对象
public static void main(String[] args) throws Exception {
Class<?> stuClass = Class.forName("Demo.Student");
System.out.println(stuClass);
//创建类的实例
Object obj = stuClass.newInstance();
System.out.println(obj);
}
//输出结果
// class Demo.Student
// Student [name=null, age=null]
通过类对象调用方法、属性等
public class Demo {
public static void main(String[] args) throws Exception {
Student stu = new Student("admin",11);
//获取方法——>Method
Class<?> stuClass = Class.forName("Demo.Student");//获取class
Method md = stuClass.getMethod("show"); //获取公有方法
md.invoke(stu); //执行方法 (参数表示要执行哪个对象的此方法)
Method mdDec = stuClass.getDeclaredMethod("show"); //获取私有方法
mdDec.setAccessible(true); //获取调用私有方法的权限
mdDec.invoke(stu); //执行
//获取属性——>Field
Field field = stuClass.getField("age"); //获取公有属性
System.out.println(field.get(stu)); //打印
Field fieldP = stuClass.getDeclaredField("name"); //获取私有属性
fieldP.setAccessible(true); //获取私有属性权限
System.out.println(fieldP.get(stu)); //打印
}
//输出结果
// 用户名:admin,年龄:11!
// 用户名:admin,年龄:11!
// 11
// admin
}
获取Class对象的摘要信息
Class<?> stuClass = Class.forName("Demo.Student");//获取class
boolean isPrimitive = stuClass.isPrimitive();//判断是否是基础类型
boolean isArray = stuClass.isArray();//判断是否是集合类
boolean isAnnotation = stuClass.isAnnotation();//判断是否是注解类
boolean isInterface = stuClass.isInterface();//判断是否是接口类
boolean isEnum = stuClass.isEnum();//判断是否是枚举类
boolean isAnonymousClass = stuClass.isAnonymousClass();//判断是否是匿名内部类
boolean isAnnotationPresent = stuClass.isAnnotationPresent(Deprecated.class);//判断是否被某个注解类修饰
String className = stuClass.getName();//获取class名字 包含包名路径
Package aPackage = stuClass.getPackage();//获取class的包信息
String simpleName = stuClass.getSimpleName();//获取class类名
int modifiers = stuClass.getModifiers();//获取class访问权限
Class<?>[] declaredClasses = stuClass.getDeclaredClasses();//内部类
Class<?> declaringClass = stuClass.getDeclaringClass();//外部类
通过反射机制获取注解信息
// 获取方法——>Method
Class<?> stuClass = Class.forName("Demo.Student");// 获取class
// 首先需要获得与该方法对应的Method对象
Method method = stuClass.getDeclaredMethod("show");
Annotation[] annotations1 = method.getAnnotations();// 获取所有的方法注解信息
TypeVariable[] typeVariables1 = method.getTypeParameters();
Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();// 拿到所有参数注解信息
Class<?>[] parameterTypes = method.getParameterTypes();// 获取所有参数class类型
Type[] genericParameterTypes = method.getGenericParameterTypes();// 获取所有参数的type类型
Class<?> returnType = method.getReturnType();// 获取方法的返回类型
int modifiers = method.getModifiers();// 获取方法的访问权限
反射机制的好处及应用场景
反射机制的好处 | 应用场景 |
---|---|
在运行时判定任意一个对象所属的类 | 逆向代码 ,例如反编译 |
在运行时构造任意一个类的对象 | 与注解相结合的框架 |
在运行时判定任意一个类所具有的成员变量和方法 | 单纯的反射机制应用框架 |
在运行时调用任意一个对象的方法 | 动态生成类框架(GSon) |
- **优点:**运行期类型的判断,动态类加载,动态代理使用反射。
- **缺点:**性能是一个问题,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。
文尾
文章均为学习阶段记录笔记,若有不妥请留言指正。谢谢!