反射注解与动态代理

反射,注解和动态代理,类加载

一、反射

1、概念
  • java的反射机制指的是程序在运行过程中,对于类,能获取到类的属性和方法,对于对象,能够调用他的属性和方法,动态的获取数据。
1、获取类的属性和方法
  • 假设有一个Student类,
1
2
3
4
5
6
7
8
9
10
/**
* class
*/
public class Student {
public String name;

public void doHomeWork(){
//do something
}
}
  • 获取类名和属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {

public static void main(String[] args) {
Class stuClass = Student.class;
System.out.println(stuClass.getName());
Field[] fields = stuClass.getFields();
Method[] methods = stuClass.getMethods();
for(Field field : fields){
System.out.println(field.getName());
}
for(Method method : methods){
System.out.println(method.getName());
}
}
}
  • 此外,也可以访问私有方法,通过 class.getDeclaredMethod(“privateMethod”, String.class, int.class)可以获取。

二、注解

  • 注解可以使得Java源代码中可以添加功能性的实现代码,还可以添加元数据,和类于接口一样,注解也属于一种类型,使用@interface进行标记,比如定义一个Hello注解
1
2
3
4
5
6
7
8
9
10
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Hello {

}
  • 使用场景,当类,属性和对象标记注解以后,注解的信息提取使用java反射的形式,主要给编译器以及工具类型的软件使用。
2.1 元注解
  • 元注解是标记注解的注解,元注解可以指明注解是做什么的,常用的有:
  • @Retention 注解的保留期,取值有RetentionPolicy.SOURCE(注解在源码期间保留), RetentionPolicy.CLASS(保留到编译进行的时候,不会加载进jvm) RetentionPolicy.RUNTIME(保留到程序运行时)
  • @Document 将注解的元素包含到java doc中
  • @Target 注解使用的地方,可以指定类,属性或者方法等,有较多选择
  • @Inherited 继承功能,当超类使用了这个注解,他的子类也会使用上这个注解。
  • @Repeatable 可重复

三、动态代理

  • 代理模式,中间人模式,常见的场景是用户要做一件事情,不会自己亲自做,而是会让中介去做,帮自己实现,面向对象程序设计中很常见的设计模式。代理流程如下:
  • 动态代理可以用来做方法的功能增强,对代码无侵入,动态代理使用Proxy的静态方法newProxyInstance动态创建代理,如下
1
2
3
public static Object newProxyInstance(ClassLoader loader,//类加载器
Class<?>[] interfaces, //代理接口
InvocationHandler h)//关联接口
  • 要创建动态代理,核心是要实现InvocationHandler接口和invoke方法,比如,要为一个接口的功能实现进行日志打印,相关流程:
1
2
3
4
5
//动态代理只能为接口创建代理
interface Work{
void getInfo();
void doWork();
}
1
2
3
4
5
6
7
8
9
10
11
12
public class HomeWork implements Work{

@Override
public void getInfo(){
System.out.println("收集资料");
}

@Override
public void doWork(){
System.out.println("正式工作");
}
}
1
2
3
4
5
6
   //增强功能
public class WorkLog {
public void log(){
System.out.println("工作记录......");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class WorkInvocationHandler implements InvocationHandler {

private Object target;

public void setTarget(Object target){
this.target = target;
}

//注意抛出异常,实现invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
WorkLog workLog = new WorkLog();
workLog.log();

return method.invoke(target, args);

}
}
1
2
3
4
5
6
7
8
9
10
11
12
    import java.lang.reflect.Proxy;

class MyProxyFactory{

public static Object getProxy(Object target) throws Exception{
// 实例化对象
WorkInvocationHandler handler = new WorkInvocationHandler();
handler.setTarget(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),handler);
}
}
1
2
3
4
5
6
7
8
9
10
    public static void main(String[] args) {
// 实例化一个被代理对象
try {
Work target = new HomeWork();
Work work = (Work) MyProxyFactory.getProxy(target);
work.getInfo();
work.doWork();
}catch (Exception ignored){}

}

四、类加载机制

1、概述
  • Java代码需要运行,首先需要将源代码进行编译生成 .class 文件,然后 JVM 加载 .class 字节码文件到内存,而 .class 文件是怎样被加载到 JVM 中的就是Java 类加载
2、分类
  • AppClassLoader 应用加载器,也称为系统加载器,会加载来自CLASSPATH中的类和包,默认情况下,其它类加载器会将它作为父类加载器
  • ExtClassloader 拓展类加载器,主要加载Java的拓展类库
  • BootStrapClassLoader 启动类加载器,是最顶层的父类加载器,主要用来加载java的核心类
3、加载过程
  • 加载流程如下:
    • 加载过程采用双亲委派模型,当一个类加载器收到类加载任务时,会有限交给父类处理,父类无法完成时才会尝试自行加载任务。保证了使用不同的类加载器最终得到的都是同一个对象。

热评文章