一、什么是注釋
??? 說起注釋,得先提一提什么是元數(shù)據(jù)(metadata)。所謂元數(shù)據(jù)就是數(shù)據(jù)的數(shù)據(jù)。也就是說,元數(shù)據(jù)是描述數(shù)據(jù)的。就象數(shù)據(jù)表中的字段一樣,每個(gè)字段描 述了這個(gè)字段下的數(shù)據(jù)的含義。而J2SE5.0中提供的注釋就是java源代碼的元數(shù)據(jù),也就是說注釋是描述java源代碼的。在J2SE5.0中可以自 定義注釋。使用時(shí)在@后面跟注釋的名字。
????????????????????????????????????????????????????????????????????????????????????
二、J2SE5.0中預(yù)定義的注釋
??? 在J2SE5.0的java.lang包中預(yù)定義了三個(gè)注釋。它們是Override、Deprecated和SuppressWarnings。下面分別解釋它們的含義。
Override
??? 這個(gè)注釋的作用是標(biāo)識某一個(gè)方法是否覆蓋了它的父類的方法。那么為什么要標(biāo)識呢?讓我們來看看如果不用Override標(biāo)識會發(fā)生什么事情。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class ParentClass1 { public void myMethod1() {...} } class Class1 extends ParentClass1 { public void myMethod2() {...} }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> ParentClass1 c1 = new Class1(); c1.myMethod1();
?? 如果我們使用Override來修飾Class1中的myMethod1方法,當(dāng)myMethod1被誤寫成別的方法時(shí),編譯器就會報(bào)錯(cuò)。因此,就可以避免這類錯(cuò)誤。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class Class1 extends ParentClass1 { ?@Override // 編譯器產(chǎn)生一個(gè)錯(cuò)誤 public void myMethod2() {...} }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class Class1 extends ParentClass1 { @Override public void myMethod1() {...} }
Deprecated
????這個(gè)注釋是一個(gè)標(biāo)記注釋。所謂標(biāo)記注釋,就是在源程序中加入這個(gè)標(biāo)記后,并不影響程序的編譯,但有時(shí)編譯器會顯示一些警告信息。
???
??? 那么Deprecated注釋是什么意思呢?如果你經(jīng)常使用eclipse等IDE編寫java程序時(shí),可能會經(jīng)常在屬性或方法提示中看到這個(gè)詞。如果某 個(gè)類成員的提示中出現(xiàn)了個(gè)詞,就表示這個(gè)并不建議使用這個(gè)類成員。因?yàn)檫@個(gè)類成員在未來的JDK版本中可能被刪除。之所以在現(xiàn)在還保留,是因?yàn)榻o那些已經(jīng) 使用了這些類成員的程序一個(gè)緩沖期。如果現(xiàn)在就去了,那么這些程序就無法在新的編譯器中編譯了。
??? 說到這,可能你已經(jīng)猜出來了。Deprecated注釋一定和這些類成員有關(guān)。說得對!使用Deprecated標(biāo)注一個(gè)類成員后,這個(gè)類成員在顯示上就會有一些變化。在eclipse中非常明顯。讓我們看看圖1有哪些變化。
圖1 加上@Deprecated后的類成員在eclipse中的變化
??? 從上圖可以看出,有三個(gè)地方發(fā)生的變化。紅色框里面的是變化的部分。
??? 1. 方法定義處
??? 2. 方法引用處
??? 3. 顯示的成員列表中
??? 發(fā)生這些變化并不會影響編譯,只是提醒一下程序員,這個(gè)方法以后是要被刪除的,最好別用。
??? Deprecated注釋還有一個(gè)作用。就是如果一個(gè)類從另外一個(gè)類繼承,并且override被繼承類的Deprecated方法,在編譯時(shí)將會出現(xiàn)一個(gè)警告。如test.java的內(nèi)容如下:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class Class1 { @Deprecated public void myMethod() {} } class Class2 extends Class1 { public void myMethod() {} }
??? 注意:test.java 使用或覆蓋了已過時(shí)的 API。
??? 注意:要了解詳細(xì)信息,請使用 -Xlint:deprecation 重新編譯
??? 使用-Xlint:deprecation顯示更詳細(xì)的警告信息:
??? test.java:4: 警告:[deprecation] Class1 中的 myMethod() 已過時(shí)
??? public void myMethod()
??? ^
??? 1 警告
??? 這些警告并不會影響編譯,只是提醒你一下盡量不要用myMethod方法。
??? SuppressWarnings
??? 這個(gè)世界的事物總是成對出現(xiàn)。即然有使編譯器產(chǎn)生警告信息的,那么就有抑制編譯器產(chǎn)生警告信息的。
??? SuppressWarnings注釋就是為了這樣一個(gè)目的而存在的。讓我們先看一看如下的代碼。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public void myMethod() { List wordList = new ArrayList(); wordList.add( " foo " ); }
??? 注意:Testannotation.java 使用了未經(jīng)檢查或不安全的操作。
??? 注意:要了解詳細(xì)信息,請使用 -Xlint:unchecked 重新編譯。
??? 這兩行警告信息表示List類必須使用范型才是安全的,才可以進(jìn)行類型檢查。如果想不顯示這個(gè)警告信息有兩種方法。一個(gè)是將這個(gè)方法進(jìn)行如下改寫:
public void myMethod()
{
??List<String> wordList = new ArrayList<String>();
??wordList.add("foo");
}
另外一種方法就是使用@SuppressWarnings。
@SuppressWarnings (value={"unchecked"})
public void myMethod()
{
??List wordList = new ArrayList();
??wordList.add("foo");
}
要注意的是SuppressWarnings和前兩個(gè)注釋不一樣。這個(gè)注釋有一個(gè)屬性。當(dāng)然,還可以抑制其它警告,如:
@SuppressWarnings (value={"unchecked", "fallthrough"})
三、如何自定義注釋
??? 注釋的強(qiáng)大之處是它不僅可以使java程序變成自描述的,而且允許程序員自定義注釋。注釋的定義和接口差不多,只是在interface前面多了一個(gè)“@”。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public @interface MyAnnotation { }
??? 當(dāng)然,也可以定義有屬性的注釋。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public @interface MyAnnotation { ??String value(); }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @MyAnnotation("abc") public void myMethod() { }
??? 除了可以省略屬性名,還可以省略屬性值。這就是默認(rèn)值。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public @interface MyAnnotation { ??public String myMethod() {} default “xyz”; }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @MyAnnotation // 使用默認(rèn)值xyz public void myMethod() { }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @MyAnnotation(myMethod = ”abc”) public void myMethod() { }
??? 如果要使用多個(gè)屬性的話。可以參考如下代碼。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public @interface MyAnnotation { public enum MyEnum {A, B, C} public MyEnum.value1() {} public String value2() {} } @MyAnnotation(value1 = MyAnnotation.MyEnum.A, value2 = “xyz”) public void myMethod() { }
四、如何對注釋進(jìn)行注釋
??? 這一節(jié)的題目讀起來雖然有些繞口,但它所蘊(yùn)涵的知識卻對設(shè)計(jì)更強(qiáng)大的java程序有很大幫助。
在上一節(jié)討論了自定義注釋,由此我們可知注釋在J2SE5.0中也和類、接口一樣。是程序中的一個(gè)基本的組成部分。既然可以對類、接口進(jìn)行注釋,那么當(dāng)然也可以對注釋進(jìn)行注釋。
??? 使用普通注釋對注釋進(jìn)行注釋的方法和對類、接口進(jìn)行注釋的方法一樣。所不同的是,J2SE5.0為注釋單獨(dú)提供了4種注釋。它們是Target、 Retention、Documented和Inherited。下面就分別介紹這4種注釋。
?? Target
?? 這個(gè)注釋理解起來非常簡單。由于target的中文意思是“目標(biāo)”,因此,我們可能已經(jīng)猜到這個(gè)注釋和某一些目標(biāo)相關(guān)。那么這些目標(biāo)是指什么呢?大家可以先看看下面的代碼。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @Target( ElementType.METHOD ) @interface MyAnnotation {} @MyAnnotation // 錯(cuò)誤的使用 public class Class1 { @MyAnnotation // 正確的使用 public void myMethod1() {} }
??
說到這,大家可能已經(jīng)基本明白了。原來target所指的目標(biāo)就是java的語言元素。如類、接口、方法等。當(dāng)然,Target還可以對其它的語言元素進(jìn)行限制,如構(gòu)造函數(shù)、字段、參數(shù)等。如只允許對方法和構(gòu)造函數(shù)進(jìn)行注釋可以寫成:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @Target( {ElementType.METHOD, ElementType.CONSTRUCTOR} ) @interface MyAnnotation {}
???? 既然可以自定義注釋,當(dāng)然也可以讀取程序中的注釋(如何讀取注釋將在下一節(jié)中討論)。但是注釋只有被保存在class文件中才可以被讀出來。而 Retention就是為設(shè)置注釋是否保存在class文件中而存在的。下面的代碼是Retention的詳細(xì)用法。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @Retention(RetentionPolicy.SOURCE) @interface MyAnnotation1 { } @Retention(RetentionPolicy.CLASS) @interface MyAnnotation2 {} @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3 {}
Documented
??? 這個(gè)注釋和它的名子一樣和文檔有關(guān)。在默認(rèn)的情況下在使用javadoc自動生成文檔時(shí),注釋將被忽略掉。如果想在文檔中也包含注釋,必須使用Documented為文檔注釋。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @interface MyAnnotation { } @MyAnnotation class Class1 { public void myMethod() { } }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class Class1extends java.lang.Object 而如果這樣定義MyAnnotation將會出現(xiàn)另一個(gè)結(jié)果。 @Documented @interface MyAnnotation {} 生成的文檔: @MyAnnotation // 這行是在加上@Documented后被加上的 class Class1extends java.lang.Object
???? 繼承是java主要的特性之一。在類中的protected和public成員都將會被子類繼承,但是父類的注釋會不會被子類繼承呢?很遺憾的告訴大家, 在默認(rèn)的情況下,父類的注釋并不會被子類繼承。如果要繼承,就必須加上Inherited注釋。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @Inherited @interface MyAnnotation { } @MyAnnotation public class ParentClass {} public class ChildClass extends ParentClass { } 在以上代碼中ChildClass和ParentClass一樣都已被MyAnnotation注釋了。
五、如何使用反射讀取注釋
??? 前面討論了如何自定義注釋。但是自定義了注釋又有什么用呢?這個(gè)問題才是J2SE5.0提供注釋的關(guān)鍵。自定義注釋當(dāng)然是要用的。那么如何用呢?解決這個(gè)問題就需要使用java最令人興奮的功能之一:反射(reflect)。
在以前的JDK版本中,我們可以使用反射得到類的方法、方法的參數(shù)以及其它的類成員等信息。那么在J2SE5.0中同樣也可以象方法一樣得到注釋的各種信息。
??? 在使用反射之前必須使用import java.lang.reflect.* 來導(dǎo)入和反射相關(guān)的類。
??? 如果要得到某一個(gè)類或接口的注釋信息,可以使用如下代碼:
Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);
如果要得到全部的注釋信息可使用如下語句:
Annotation[] annotations = TestAnnotation.class.getAnnotations();
或
Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();
getDeclaredAnnotations與getAnnotations類似,但它們不同的是getDeclaredAnnotations得到的 是當(dāng)前成員所有的注釋,不包括繼承的。而getAnnotations得到的是包括繼承的所有注釋。
??? 如果要得到其它成員的注釋,可先得到這個(gè)成員,然后再得到相應(yīng)的注釋。如得到myMethod的注釋。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> Method method = TestAnnotation. class .getMethod( " myMethod " , null ); Annotation annotation = method.getAnnotation(MyAnnotation. class ); 注:要想使用反射得到注釋信息,這個(gè)注釋必須使用 @Retention(RetentionPolicy.RUNTIME)進(jìn)行注釋。
總結(jié)
??? 注釋是J2SE5.0提供的一項(xiàng)非常有趣的功能。它不但有趣,而且還非常有用。EJB3規(guī)范就是借助于注釋實(shí)現(xiàn)的。這樣將使EJB3在實(shí)現(xiàn)起來更簡單,更 人性化。還有Hibernate3除了使用傳統(tǒng)的方法生成hibernate映射外,也可以使用注釋來生成hibernate映射。總之,如果能將注釋靈 活應(yīng)用到程序中,將會使你的程序更加簡潔和強(qiáng)大。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
