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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM