zoukankan      html  css  js  c++  java
  • java自定义注解类

    一、前言

      今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下。

    二、代码示例

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.reflect.Field;
    
    //自定义注解类 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @
    interface MyAnnotation { String name() default "hjzgg"; } public class Main { public Main(Class cls) { Field[] fields = cls.getDeclaredFields(); TestAnnotation obj = null; try { obj = (TestAnnotation)cls.getConstructors()[0].newInstance(this);//获取内部类对象 } catch (Exception e) { e.printStackTrace(); } for(Field field : fields) { System.out.println(field.getName() + " " + field.getType().getName()); if(!field.getName().equals("this$0")) { MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);//获取注解类 String name = annotation.name(); field.setAccessible(true); try { switch(name) { case "hjzgg": switch(field.getType().getName()) { case "int": case "java.lang.Integer": field.set(obj, 555); break; case "java.lang.String": field.set(obj, "hehe"); break; } break; case "lxkdd": switch(field.getType().getName()) { case "int": case "java.lang.Integer": field.set(obj, 555); break; case "java.lang.String": field.set(obj, "hehe"); break; } break; default: break; } } catch (Exception e) { e.printStackTrace(); } } } System.out.println(obj); } public static void main(String[] args) throws InstantiationException, IllegalAccessException { new Main(TestAnnotation.class); } class TestAnnotation{ public TestAnnotation(){} @MyAnnotation(name="lxkdd") private int x; @MyAnnotation private String y; public int getX() { return x; } public void setX(int x) { this.x = x; } public String getY() { return y; } public void setY(String y) { this.y = y; } @Override public String toString() { return "x: " + x + ", y: " + y; } } }

    三、代码分析

      1.如何编写自定义注解

    public @interface MyAnnotation {   
        String value() default "hahaha";   
    }  

      感觉等价于

    public class MyAnnotation extends java.lang.annotation.Annotation{   
         private String value = "hahaha";   
         public void setValue(String value){   
              this.value = value;   
         }   
         public String getValue(){   
              return value;   
          }   
    } 

      自定义注解类规则

      @interface实际上是继承了java.lang.annotation.Annotation,所以定义annotation时不能继承其他annotation或interface. java.lang.annotation.Retention告诉编译器如何对待 Annotation,使用Retention时,需要提供java.lang.annotation.RetentionPolicy的枚举值.

    public enum RetentionPolicy {   
        SOURCE, // 编译器处理完Annotation后不存储在class中   
        CLASS, // 编译器把Annotation存储在class中,这是默认值   
        RUNTIME // 编译器把Annotation存储在class中,可以由虚拟机读取,反射需要   
    }   

        java.lang.annotation.Target告诉编译器Annotation使用在哪些地方,使用需要指定java.lang.annotation.ElementType的枚举值.

    public enum ElementType {   
        TYPE, // 指定适用点为 class, interface, enum   
        FIELD, // 指定适用点为 field   
        METHOD, // 指定适用点为 method   
        PARAMETER, // 指定适用点为 method 的 parameter   
        CONSTRUCTOR, // 指定适用点为 constructor   
        LOCAL_VARIABLE, // 指定使用点为 局部变量   
        ANNOTATION_TYPE, //指定适用点为 annotation 类型   
        PACKAGE // 指定适用点为 package   
    }   

        java.lang.annotation.Documented用于指定该Annotation是否可以写入javadoc中. 
        java.lang.annotation.Inherited用于指定该Annotation用于父类时是否能够被子类继承. 

      示例

    import java.lang.annotation.ElementType;   
    import java.lang.annotation.Retention;   
    import java.lang.annotation.RetentionPolicy;   
    import java.lang.annotation.Target;   
      
    @Documented  //这个Annotation可以被写入javadoc   
    @Inherited       //这个Annotation 可以被继承   
    @Target({ElementType.CONSTRUCTOR,ElementType.METHOD}) //表示这个Annotation只能用于注释 构造子和方法   
    @Retention(RetentionPolicy.CLASS) //表示这个Annotation存入class但vm不读取   
    public @interface MyAnnotation {   
        String value() default "hahaha";   
    }  

      2.如何获取自定义注解

       java.lang.reflect.AnnotatedElement接口提供了四个方法来访问Annotation

    public Annotation getAnnotation(Class annotationType);   
    public Annotation[] getAnnotations();   
    public Annotation[] getDeclaredAnnotations();   
    public boolean isAnnotationPresent(Class annotationType);  

       来自:http://blog.csdn.net/foamflower/article/details/5946451

       Class、Constructor、Field、Method、Package等都实现了该接口,可以通过这些方法访问Annotation信息,前提是要访问的Annotation指定Retention为RUNTIME. 
         Java内置的annotation有Override Deprecated SuppressWarnings. 
         Override只用于方法,它指明注释的方法重写父类的方法,如果不是,则编译器报错. 
         Deprecated指明该方法不建议使用.
         SuppressWarnings告诉编译器:我知道我的代码没问题.

      3.this$0是什么意思?

    public class Outer {//this$0 
      public class FirstInner {//this$1 
        public class SecondInner {//this$2 
           public class ThirdInner { 
           } 
         } 
      } 
    }

      说一个场景:当我们拿到了一个内部类的对象Inner,但是又想获取其对应的外部类Outer,那么就可以通过this$0来获取。this$0就是内部类所自动保留的一个指向所在外部类的引用。 

        //通过工具获取到Inner实例对象 
        Outer.Inner inner = getInner(); 
        //获取内部类Inner的一个字段this$0信息 
        //this$0特指该内部类所在的外部类的引用,不需要手动定义,编译时自动加上 
        Filed outerField = inner.getClass().getDeclaredField("this$0"); 
        //this$0是私有的,提升访问权限 
        outerField.setAccessible(true); 
        //拿到该字段上的实例值 
        Outer outer = (Outer)outerField.get(inner); 

      4.java如何反射内部类

    Class<?> cls = Class.forName("package.OuterClass$InnerClass"); or Class<?> cls = OuterClass.InnerClass.class;
    (1)OuterClass.InnerClass obj = (OuterClass.InnerClass)cls.getConstructors()[0].newInstance(new OuterClass()); 
    (2)OuterClass.InnerClass obj
    = (OuterClass.InnerClass)cls.getConstructor(OuterClass.class).newInstance(new OuterClass());

      由此可见,内部类的无参构造器在通过反射机制获取时,要指定其父类参数才可以获得,否则将报如下异常:

    java.lang.NoSuchMethodException: com.hjzgg.OuterClass$InnerClass.<init>()
        at java.lang.Class.getConstructor0(Class.java:3082)
        at java.lang.Class.getConstructor(Class.java:1825)
  • 相关阅读:
    C++ 线程的创建、挂起、唤醒和结束 &&&& 利用waitForSingleObject 函数陷入死锁的问题解决
    接收数据界面卡顿-----待整理
    vs2012 在调试或运行的过程中不能加断点
    matlab 学习笔记
    周立功USBCAN-II 上位机开发(MFC)
    vs添加静态链接库+添加动态链接库+添加头文件目录
    Go 面试每天一篇(第 2 天)
    http 协议
    Samba配置
    svn checkout 单个文件
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/5719611.html
Copyright © 2011-2022 走看看