代理 及 注解

代理(Proxy)

Proxy代理类的理解:

在系统程序设计中,有时需要面对无法确定接口,却需要构造对象的情况。通过代理类,能够在不额外创建Java文件的情况下构造对象及调用该对象方法。(系统程序设计用得较多,应用程序设计遇到的情况比较少)

代理类可以在运行时创建全新的类,这样的代理类能够实现指定的接口,尤其是,它具有下列方法:

  • 指定接口所需要的全部方法。
  • Object类中的全部方法,例如:toString ,equals等等。

但是不能在运行时定义这些方法的新代码,而是要提供一个调用处理器(invocationhandler),调用处理器实现了InvocationHandler接口的类对象。

调用处理器

InvocationHandler 这个接口只有一个方法。这个方法定义了代理对象调用方法时希望执行的动作。即方法具体要做什么…

Object invoke(Object proxy, Method method, Object[] args)

  • 第一个参数为代理类本身
  • 第二个参数为method 对象
  • 第三个参数为其原始的调用参数

在这个调用处理器的方法中,必须给出处理调用的方式,

创建代理对象

想要创建一个代理对象,需要使用Proxy类的newProxyInstance 方法。该方法构造一个实现指定接口的代理类的实例,所有方法都将调用给调用处理器(InvocationHandler)的invoke方法。

static Object newProxyInstance(ClassLoader loader Class[] interfaces, InvocationHandler handler)

  • 第一个参数为 类加载器,使用null表示使用默认的类加载器(这个另行查阅)
  • 第二个参数为一个Class对象数组,每个元素都是需要实现的接口
  • 第三个参数为调用处理器

例子:见代码

其他:

  • 代理类是在程序运行过程中创建的。然而,一旦被创建,就变成了常规类,与虚拟机中的其他任何类没有区别。
  • 所有代理类都扩展于Proxy类,一个代理类只有一个实例域——调用处理器,它定义在Proxy的超类中。
  • 所有的代理类都覆盖了Object类中的方法toString,equals,hashCode.如同所有的代理方法一样,这些方法仅仅调用了调用处理器的Invoke。其他方法没有被重新定义。
  • 对于特定的类加载器和预设的一组接口来说,只能有一个代理类。可以通过 getProxyClass()方法获得这个类
    Class proxyClass = Proxy.getProxyClass(null, interface);
    第一个参数为ClassLoader 第二个参数为 接口对象数组
  • 可以通过isProxyClass(Class c) 来判断一个类是否为代理类。

注解(Annotation)

  • 注解是那些插入到源代码中使用其他工具可以对其进行处理的标签。

  • 为了能够受益于注解。需要选择一个处理工具,然后向处理工具可以理解的代码中插入注解,之后运用该处理工具处理代码。
    任何一个注解自身不会做任何事情,他需要工具支持才会有用。一般为代理类

  • 在Java中,注解是当作一个修饰符来使用的,它被置于被注解项之前,中间没有分号。每个注解的名称前面都加上了@ 符号。类似于javadoc的注释,但是注解是代码的一部分。
  • 所有注解接口都隐式的扩展自 java.lang.annotation.Annotation接口,这个接口是一个常规接口,不是注解接口。注解接口无法扩展
  • 一个项可以有多个注解,只要它们是不同的类型即可。

自定义注解

/**
 * 标记网络请求基本设置, 请求类型
 * Created by wangyy on 2016/5/23.
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IRequest {
    enum METHOD {POST, GET, PUT, DELETE}

    METHOD method() default METHOD.POST; // 默认值为动态计算的,而不是和注解存储在一起的
    String url();
}
@IRequest(url = "/user/loginMobile")
VolleyRequest<UserInfo> login(@IBody Map<String, Object> params, @IHeader("aaa") Map<String, Object> params); // 登录

有两种特殊的快捷方式可以简化注解:

  • 如果没有指定元素,要么是因为注解中没有任何元素,要么是因为所有元素都使用默认值,那么久可以不用圆括号。如@IBody。又称为标记注解
  • 单值注解。如果一个元素具有特殊的名字value,并且没有指定其他元素,就可以忽略掉这个元素名以及等号。如 @IHeader(“aaa”)

注解接口中的元素声明实际上是方法声明。一个注解接口的方法不能有任何参数和throws语句,并且他们也不能是泛型的。注解元素的类型:

  • 基本类型
  • String
  • Class
  • enum 类型
  • 注解类型 // 可以声明一个注解,有多个更简单的注解组成
  • 由前面所述类型组成的数组
Public @interface BugReport{
    enum Status{UNCONFIRMED, CONFIRMED, FIXED, NOTABUG}
    boolean showstopper() default false;
    String assignedTo() default “”;
    Class<?> testCase() default void.class;
    Status status() default Status.FIXED;
    Reference ref default @Reference();// an annotation type
    String[] reportedBy();
}

标准注解

用于编译的注解:
  • @Override 告诉编译器这个方法要覆盖一个超类方法,防止程序员覆盖出错。
  • @Deprecated 这个标识方法或类(接口等类型)过期,警告用户不建议使用。
  • @SafeVarargs JDK7新增,避免可变参数在使用泛型化时候警告”执行时期无法具体确认参数类型“,当然,也可以用@SuppressWarnings来避免检查,显然后者的抑制的范围更大。
  • @SuppressWarnings(value={“unchecked”}) 抑制编译警告,应用于类型、构造器、方法、域、参数以及局部变量。
  • @Generated
用于管理资源的注解:
  • @PostConstruct, @PreDestroy
  • @Resource

元注解

@Target

可以应用于一个注解,以限制该注解可以应用到哪些项上。如@Target({ElementType.METHOD})

public enum ElementType {
    /**
     * Class, interface or enum declaration. 类及接口包括enum,注解类型
     */
    TYPE,
    /**
     * Field declaration. 成员域(包括enum常量)
     */
    FIELD,
    /**
     * Method declaration. 方法
     */
    METHOD,
    /**
     * Parameter declaration. 方法或构造器参数
     */
    PARAMETER,
    /**
     * Constructor declaration. 构造器
     */
    CONSTRUCTOR,
    /**
     * Local variable declaration. 局部变量
     */
    LOCAL_VARIABLE,
    /**
     * Annotation type declaration. 注解类型声明
     */
    ANNOTATION_TYPE,
    /**
     * Package declaration. 包
     */
    PACKAGE
}

自己本身也是一个注解,注解可以用于自己

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE) // 应用于注解类型声明
public @interface Target {
    ElementType[] value();
}
@Retention

用于指定一条注解应该保留多长时间。 如@Retention(RetentionPolicy.RUNTIME)

public enum RetentionPolicy {
    /**
     *不包括在类文件中的注解
     */
    SOURCE,
    /**
     * 包括在类文件中的注解,但是虚拟机不需要将他们载入
     */
    CLASS,
    /**
     * 包括在类文件中的注解,并由虚拟机载入,通过反射API可获得它们
     */
    RUNTIME
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}
@Decumented

为像Javadoc这样的归档工具提供了一些提示

@Inherited

只能应用于对类的注解。指明当这个注解应用于一个类的时候,能够自动被它的子类继承

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 Java 的反射机制来获取方法上的注解,并通过代理来修改注解的值。具体实现可以参考以下代码: ```java import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class AnnotationProxy { public static void main(String[] args) throws Exception { // 获取需要修改注解的方法 Method method = MyClass.class.getMethod("myMethod"); // 获取方法上的注解 MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); // 创建代理对象 MyAnnotation proxyAnnotation = (MyAnnotation) Proxy.newProxyInstance( MyAnnotation.class.getClassLoader(), new Class[]{MyAnnotation.class}, (proxy, method1, args1) -> { // 修改注解的值 if (method1.getName().equals("value")) { return "new value"; } else { return method1.invoke(annotation, args1); } }); // 修改方法上的注解 Annotation[] annotations = method.getDeclaredAnnotations(); for (int i = 0; i < annotations.length; i++) { if (annotations[i].annotationType() == MyAnnotation.class) { annotations[i] = proxyAnnotation; } } // 调用方法 MyClass myClass = new MyClass(); myClass.myMethod(); } @MyAnnotation("old value") static class MyClass { public void myMethod() { System.out.println("Hello, world!"); } } @interface MyAnnotation { String value(); } } ``` 在上面的代码中,我们使用了 Java 的反射机制来获取方法上的注解,并通过代理来修改注解的值。具体来说,我们创建了一个代理对象,然后在代理对象的方法中判断是否需要修改注解的值,如果需要就返回新的值,否则就调用原来的方法。最后,我们将修改后的注解赋值给方法上的注解数组,然后调用方法即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值