Java反射机制以及应用
1、Java反射
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。
2、Java程序运行大致过程
Java源文件(.java文件)–>经过Javac编译器编译–>二进制字节码文件(.class文件)–>Jvm类加载器加载–>解释器解释–>机器码(机器可理解的代码)–>操作系统平台
3、Java反射作用以及原理
3.1 反射作用
通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
3.2 反射原理
简单来说就是通过反编译,来获取类对象的属性、方法等信息。
Java的反射机制是在编译时并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用的是在编译期并不知道的类。
反编译:.class–>.java
注意:Jvm从本地磁盘把字节码文件加载到Jvm内存中,Jvm会自动创建一个class对象。即一个类只会产生一个class对象。
原因:类加载机制–双亲委派机制
4、类加载机制–双亲委派机制
JVM中提供了三层的ClassLoader:
-
BootstrapClassLoader:主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。
-
ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。
-
AppClassLoader:主要负责加载应用程序的主函数类。
双亲委派机制下类加载过程如图:
在考虑存在自定义类加载器情况下,对类的加载首先是从自定义类加载器中检查该类是否已经被加载过,如果没有被加载,则向上委托,拿到父类构造器AppClassLoader加载器进行检查,如果还是没有被加载,则依次向上委托,不断检查父类加载器是否已经加载过该类。如果已经加载,则无需进行二次加载,直接返回。如果经过BootstrapClassLoader加载器检查后,发现该类未被加载,则从父类向下开始加载该类。如果BootstrapClassLoader加载器无法加载该类,则交由子类加载器加载,依次向下加载。
双亲委派机制的作用:
- 避免相同类二次加载
- 防止核心类库API被修改
5、Java反射使用
5.1 获取类对象的三种方式
- 通过Class类中的静态方法forName,来获取类对象
Class clazz1 = Class.forName("全限定类名");
- 通过类名.class
Class clazz2 = Demo.class;
- 通过类的实例获取该类的字节码文件对象
Class clazz3 = p.getClass();
5.2 反射获取类属性、方法、构造方法
public class TargetDemo {
public TargetDemo (){}
public TargetDemo (String str){
this.str = str;
System.out.println("执行构造器方法");
}
public String str = "hello";
private String username;
private int age;
public void print(){
System.out.println("TargetDemo");
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class TestDemo {
public static void main(String[] args) {
try {
//获取类对象
Class<?> target = Class.forName("com.torlesse.consumer.test.TargetDemo");
//获取类对象属性 公共部分不能访问私有
for (Field field : target.getFields()) {
System.out.println(field.getName());
}
//获取构造器
Constructor<?> targetDeclaredConstructor = target.getDeclaredConstructor(String.class);
Object o = targetDeclaredConstructor.newInstance("demo");
System.out.println(o);
//实例化对象
Object o1 = target.newInstance();
//获取方法
Method method = target.getMethod("print");
method.invoke(o1,null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
6、运行指定包下获取被指定注解的类
方案使用:reflections框架
依赖导入:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
//标记类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JobClassInterface {
}
//标记方法的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JobMethodInterface {
String jobName();
}
//入参 要扫描的包名
Reflections f = new Reflections("com.torlesse.xxx.xxx");
//入参 目标注解类
Set<Class<?>> set = f.getTypesAnnotatedWith(JobClassInterface.class);
Iterator<Class<?>> iterator = set.iterator();
while (iterator.hasNext()){
Class<?> next = iterator.next();
for (Method method : next.getMethods()) {
for (Annotation declaredAnnotation : method.getDeclaredAnnotations()) {
if(declaredAnnotation instanceof JobMethodInterface){
String targetName = ((JobMethodInterface)declaredAnnotation).jobName();
if(targetName.equals(jobName)){
method.invoke(next.newInstance(), null);
return;
}
}
}
}
}
Java反射机制及应用