Java 8 新特性:扩展注解(类型注解和重复注解)
生活随笔
收集整理的這篇文章主要介紹了
Java 8 新特性:扩展注解(类型注解和重复注解)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載自??Java 8 新特性:擴展注解(類型注解和重復注解)
(注:先回顧下JDK1.5版本出現的注解 ,然后再解釋JDK 8的注解 更新內容。)
一.注解(JDK1.5)
1.注解(@):注解就相當于一種標記,在程序中加了注解就等于為程序加了某種標記。(JDK1.5新特性)。
2.作用:
告訴javac編譯器或者java開發工具……向其傳遞某種信息,作為一個標記。
3.了解注解:
一個注解就是一個類。
標記可以加在包、類、字段、方法,方法參數以及局部變量上。可以同時存在多個注解。
每一個注解結尾都沒有“;”或者其他特別符號。
eg:
@SuppressWarnings("deprecation") //編譯器警告過時(source階段) @Deprecated //過時(Runtime階段) @Override //重寫(source階段) @Retention(RetentionPolicy.RUNTIME) //保留注解到程序運行時。(Runtime階段) @Target({ElementType.METHOD,ElementType.TYPE}) //標記既能定義在方法上,又能定義在類、接口、枚舉上等。Note:
1)添加注解需要有注解類。RetentionPolicy是一個枚舉類(有三個成員)。
2)Target中可以存放數組。它的默認值為任何元素。
ElementType.METHOD:表示只能標記在方法上。
ElementType.TYPE:表示只能標記定義在類上、接口上、枚舉上等。
3)ElementType也是枚舉類。成員包括:ANNOTATION_TYPE(注解)、CONSTRUCTOR(構造方法)、FIEID(成員變量)、LOCAL_VARIABLE(變量)、METHOD(方法)、PACKAGE(包)、PARAMETER(參數)、TYPE。
4.注解應用結構圖:
5.簡單相關知識了解:
元注解:注解的注解(理解:給一個注解類再加注解)
元數據:數據的數據
元信息:信息的信息
6.注解分為三個階段:
java源文件--> class文件 --> 內存中的字節碼。
Retention的注解有三種取值:(分別對應注解的三個階段)
RetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME
Note:注解的默認階段是Class。
7.注解的屬性類型:
原始類型(就是八個基本數據類型)、String類型、Class類型、數組類型、枚舉類型、注解類型。
8.為注解增加屬性:
value:是一個特殊的屬性,若在設置值時只有一個value屬性需要設置或者其他屬性都采用默認值時 ,那么value=可以省略,直接寫所設置的值即可。
eg:@SuppressWarnings("deprecation")
eg:String value() default "blue"; //定義在注解類中
?
數組類型的屬性:
eg:int[] arrayArr() default {3,4,5,5};//定義在注解類中
SunAnnotation(arrayArr={3,9,8}) //設置數組值
Note:如果數組屬性中只有一個元素時,屬性值部分可以省略大括號。
eg:SunAnnotation(arrayArr=9)
?
枚舉類型的屬性:
eg:EnumDemo.TrafficLamp lamp()
default EnumDemo.TrafficLamp.RED;
//枚舉類型屬性, 定義在注解類中,這里使用了自定義的枚舉類EnumDemo.java并沒有給出相關代碼,這里只是舉個例子
注解類型的屬性:
eg:MetaAnnotation annotationAttr()
default @MetaAnnotation("lhm");
//定義在一個注解類中,并指定缺省值,
//此屬性關聯到注解類:MetaAnnotation.java,?
@SunAnnotation(annotationAttr=@MetaAnnotation("flx"))
//設置注解屬性值
9.注解應用示例:
(注:下面只是示例,涉及枚舉的類,并沒有給出相關代碼。) 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:表示只能標記在方法上。ElementType.TYPE:表示只能標記定義在類上、接口上、枚舉上等。 @Target({ElementType.METHOD,ElementType.TYPE}) public @interface SunAnnotation { String color() default "blue"; //表示有一個color屬性,以方法的形式。設置默認屬性值為藍色 String value(); //是一個特殊的屬性,若在設置值時只有一個value屬性需要設置 ,那么value可以省略,直接寫所設置的值即可。 //數組屬性 int[] arrayArr() default {3,4,5,5}; //枚舉類型屬性,這里使用了自定的枚舉類EnumDemo.java EnumDemo.TrafficLamp lamp() default EnumDemo.TrafficLamp.RED; //注解類型屬性,此時關聯到注解類:MetaAnnotation.java,并指定缺省值 MetaAnnotation annotationAttr() default @MetaAnnotation("lhm"); //Class類屬性:設置默認值 ReflectDemo.java 類 Class annotationClass() default ReflectDemo.class; } @SunAnnotation(annotationClass=ReflectDemo2.class,annotationAttr=@MetaAnnotation("flx"),color="red",value="abc",arrayArr={1,3,9}) //注解:為注解添加屬性值 //若在設置值時只有一個value屬性需要設置 ,那么value可以省略,直接寫所設置的值即可。 public class AnnotationDemo { /** * @param args */ @SunAnnotation("xyz") @SuppressWarnings("deprecation") //注解:告訴編譯器或者開發工具…… //若在設置值時只有一個value屬性需要設置 ,那么value可以省略,直接寫所設置的值即可。 //上面"deprecation"即是省略的value后的值。 public static void main(String[] args)throws Exception { System.runFinalizersOnExit(true);//中間帶橫線的部分,說明該方法已經過時了。 //檢查某注解是否存在,使用反射;并返回該注解 if(AnnotationDemo.class.isAnnotationPresent(SunAnnotation.class)) { //獲取注解 SunAnnotation annotation=(SunAnnotation)AnnotationDemo.class.getAnnotation(SunAnnotation.class); //獲取屬性值 System.out.println("屬性color值:"+annotation.color());//調用color屬性方法 System.out.println(annotation.value()); System.out.println(annotation.arrayArr().length);//這里輸出的是數組長度,不能直接輸出數組的每一個值,調用得到的是數組哈希地址值 System.out.println(annotation.lamp().nextLamp().name());//調用注解默認燈的nextLamp方法 annotation.annotationAttr().value(); //獲取類類型注解中的 類名稱 System.out.println(annotation.annotationClass()); } } @Deprecated //表示下面的方法過時了 public static void sayHello() { System.out.println("hi"); } }
二.擴展注解(JDK 8)
對于注解(也被稱做元數據),Java 8 主要有兩點改進:類型注解和重復注解。1.類型注解
1)Java 8 的類型注解擴展了注解使用的范圍。
在java 8之前,注解只能是在聲明的地方所使用,java8開始,注解可以應用在任何地方。
eg:
創建類實例
new@Interned MyObject();
類型映射
myString = (@NonNull String) str;
implements 語句中
class UnmodifiableList<T> implements@Readonly List<@Readonly T> { ... }
throw exception聲明
void monitorTemperature() throws@Critical TemperatureException { ... }
Note:
在Java 8里面,當類型轉化甚至分配新對象的時候,都可以在聲明變量或者參數的時候使用注解。
Java注解可以支持任意類型。
類型注解只是語法而不是語義,并不會影響java的編譯時間,加載時間,以及運行時間,也就是說,編譯成class文件的時候并不包含類型注解。
新增的兩個注釋的程序元素類型 ElementType.TYPE_USE 和 ElementType.TYPE_PARAMETER用來描述注解的新場合。
ElementType.TYPE_PARAMETER 表示該注解能寫在類型變量的聲明語句中。
ElementType.TYPE_USE 表示該注解能寫在使用類型的任何語句中(eg:聲明語句、泛型和強制轉換語句中的類型)。
eg:
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @interface MyAnnotation {} 3)類型注解的作用類型注解被用來支持在Java的程序中做強類型檢查。配合第三方插件工具Checker Framework(注:此插件so easy,這里不介紹了),可以在編譯的時候檢測出runtime error(eg:UnsupportedOperationException; NumberFormatException;NullPointerException異常等都是runtime error),以提高代碼質量。這就是類型注解的作用。
Note:
使用Checker Framework可以找到類型注解出現的地方并檢查。
eg:
import checkers.nullness.quals.*; public class TestDemo{ void sample() { @NonNull Object my = new Object(); } } 使用javac編譯上面的類:(當然若下載了Checker Framework插件就不需要這么麻煩了)javac -processor checkers.nullness.NullnessChecker TestDemo.java
上面編譯是通過的,但若修改代碼:
@NonNull Object my = null;
但若不想使用類型注解檢測出來錯誤,則不需要processor,正常javac TestDemo.java是可以通過編譯的,但是運行時會報 NullPointerException 異常。
為了能在編譯期間就自動檢查出這類異常,可以通過類型注解結合 Checker Framework 提前排查出來錯誤異常。
注意java 5,6,7版本是不支持注解@NonNull,但checker framework 有個向下兼容的解決方案,就是將類型注解@NonNull 用/**/注釋起來。
import checkers.nullness.quals.*; public class TestDemo{ void sample() { /*@NonNull*/ Object my = null; } } 這樣javac編譯器就會忽略掉注釋塊,但用checker framework里面的javac編譯器同樣能夠檢測出@NonNull錯誤。通過 類型注解 + checker framework 可以在編譯時就找到runtime error。
2.重復注解
允許在同一聲明類型(類,屬性,或方法)上多次使用同一個注解。
Java8以前的版本使用注解有一個限制是相同的注解在同一位置只能使用一次,不能使用多次。
Java 8 引入了重復注解機制,這樣相同的注解可以在同一地方使用多次。重復注解機制本身必須用 @Repeatable 注解。
實際上,重復注解不是一個語言上的改變,只是編譯器層面的改動,技術層面仍然是一樣的。
eg:
1)自定義一個包裝類Hints注解用來放置一組具體的Hint注解
@interface MyHints { Hint[] value(); } @Repeatable(MyHints.class) @interface Hint { String value(); }使用包裝類當容器來存多個注解(舊版本方法)
@MyHints({@Hint("hint1"), @Hint("hint2")}) class Person {}使用多重注解(新方法)
@Hint("hint1") @Hint("hint2") class Person {}2)
public class RepeatingAnnotations { @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Filters { Filter[] value(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Repeatable(Filters.class) public @interface Filter { String value(); } @Filter("filter1") @Filter("filter2") public interface Filterable { } public static void main(String[] args) { for (Filter filter : Filterable.class.getAnnotationsByType(Filter.class)) { System.out.println(filter.value()); } } } 輸出結果:filter1
filter2
分析:
注釋Filter被@Repeatable( Filters.class )注釋。Filters 只是一個容器,它持有Filter, 編譯器盡力向程序員隱藏它的存在。通過這樣的方式,Filterable接口可以被Filter注釋兩次。
另外,反射的API提供一個新方法getAnnotationsByType() 來返回重復注釋的類型(注意Filterable.class.getAnnotation( Filters.class )將會返回編譯器注入的Filters實例)。
3)java 8之前也有重復使用注解的解決方案,但可讀性不好。
public @interface MyAnnotation { String role(); } public @interface Annotations { MyAnnotation[] value(); } public class RepeatAnnotationUseOldVersion { @Annotations({@MyAnnotation(role="Admin"),@MyAnnotation(role="Manager")}) public void doSomeThing(){ } }Java8的實現方式(由另一個注解來存儲重復注解,在使用時候,用存儲注解Authorities來擴展重復注解),可讀性更強。
@Repeatable(Annotations.class) public @interface MyAnnotation { String role(); } public @interface Annotations { MyAnnotation[] value(); } public class RepeatAnnotationUseOldVersion { @MyAnnotation(role="Admin") @MyAnnotation(role="Manager") public void doSomeThing(){ } }
總結
以上是生活随笔為你收集整理的Java 8 新特性:扩展注解(类型注解和重复注解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 丁岚个人资料 关于丁岚简介
- 下一篇: java美元兑换,(Java实现) 美元