您的位置:首页 > 职场人生

黑马程序员_Jav基础加强之注解(annotation)

2013-08-25 19:15 369 查看
--------- android培训java培训、期待与您交流!----------
一、了解注解
从JDK1.5版本开始,Java增加Annotation(注解),注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,这些标记可以在编译(SOURCE)、类加载(CLASS)、运行时(RUNTIME)被读取,并执行相应的处理。通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或都进行部署。
Annotaion能被用来为程序元素(类、方法、成员变量等)设置元数据它不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一地执行。如果希望让程序中的Annotation在运行时起一定的作用,只有通过某种配套的工具对Annotation中的信息进行访问和处理,访问和处理Annotation的工具统称为APT(Annotation Processing Tool)。

二、基本Annotation
JDK1.7新增了一个,所以有4个:
@Override

@Deprecated

@SuppressWarnings

@SafeVarargs

1、限定重写父类方法:@Override
@Override只能作用于方法,不能作用于其他程序元素。它的作用是告诉编译器检查这个方法,保证父类要包含一个被该方法重写的方法,否则就会编译出错。它有助于程序员避免犯一些低级错误。
如:
class Creature
{
public void show()
{
System.out.println("生物的特征");
}
}
class Person extends Creature
{
//使用@Override指定下面方法必须重写父类方法
@Override
public void show()
{
System.out.println("人类的特征");
}
}

2、标示已过时:@Deprecated
@Deprecated用于表示某个程序元素(类、方法等)已过时,当其他程序使用已时的类、方法时,编译器将会给出警告。如下程序:
class Creature
{
//将show()方法标示成过时
@Deprecated
public void show()
{
System.out.println("生物的特征");
}
}
class DeprecatedTest
{
public static void main(String[] args)
{
//下面使用info方法时将会被编译器警告
//在Eclipse界面下,会在show方法上加一行划线来表示过时
new Creature().show();
}
}

3、抑制编译器警告:@SuppressWarnings
@SuppressWarnings指示被Annotation修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告。值得注意的是,这个标记会把作用于该程序元素的所有子元素,当它修饰的方法中有多个编译器的警告它会同时取消显示这些编译器警告。
①示例一:
package com.itheiam.blog;
import java.util.ArrayList;
//关闭整个类里的编译时期发生的警告
//也可以写成@SuppressWarnings("unchecked")
@SuppressWarnings(value="unchecked")
public class SuppressWarningTest
{
public static void main(String[] args)
{
ArrayList<String> myList = new ArrayList();
}
}
//如果以上不用标记,那么会产生以下警告:
/*注: SuppressWarningTest.java使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。*/
注:如果Annotation里只有一个value成员变量,使用该Annotation时可以直接在Annotation后的括号里指定value成员变量的值,无须使用name=value的形式。
②示例二:
import java.util.*;
class AnnotationTest{
//标记对已经过时的不再提醒
//也可以写成@SuppressWarnings(value="deprecation")
@SuppressWarnings("deprecation")
/*经测试不能用以下方式来标记,虽然不会报错,但起不到任何效果
@SuppressWarnings(value="unchecked")*/
public static void main(String[] args) {
System.runFinalizersOnExit(true);
}
}
③示例三:
//当警告的提示不是同一信息的时候,还是要分别对它们标记。
import java.util.*;
@SuppressWarnings(value="unchecked")
public class SuppressWarningTest {
public static void main(String[] args) {
ArrayList<String> myList = new ArrayList();
}
@SuppressWarnings("deprecation")
public void test(){
boolean bool = false;
System.runFinalizersOnExit(bool);
}
}

4、"堆污染"警告与@SafeVarargs
Java把引发这种错误原因称为"堆污染"(Heap pollution),当把一个不带泛型的对象赋给泛型的变量时,往往会发生这种"堆污染",如上①所在行代码所示。
import java.util.*;
class test2
{
public static void main(String[] args)
{
m(Arrays.asList("hello"));
}
@SafeVarargs // Not actually safe!
public  static void m(List<String>... stringLists)
{
Object[] array = stringLists;
List<Integer> tmpList = Arrays.asList(42);
// Semantically invalid, but compiles without warnings
//下面这句话语义无效,但编译的时候没有带任何警告
array[0] = tmpList;//①
String s = stringLists[0].get(0);
//上面这句话话在运行时会发生:java.lang.ClassCastException
}
}
//当不采用@SafeVarargs时,在编译时期就会发生如下警告:
/*注: test2.java使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。*/
/*也可以采用@SuppressWarnings("unchecked")来标记,但是必须在类上标记,否则无效
即使在方法体上标记也是没有用的*/
如:
import java.util.*;
@SuppressWarnings("unchecked")
class test2
{
//@SuppressWarnings("unchecked")在此标记也无效
public static void main(String[] args)
{
m(Arrays.asList("hello"));
}
//@SuppressWarnings("unchecked")在此标记无效
public  static void m(List<String>... stringLists)
{
Object[] array = stringLists;
List<Integer> tmpList = Arrays.asList(42);
// Semantically invalid, but compiles without warnings
//下面这句话语义无效,但编译的时候没有带任何警告
array[0] = tmpList;//①
String s = stringLists[0].get(0);
//上面这句话话在运行时会发生:java.lang.ClassCastException
}
}

三、元 Annotation(Meta Annotation)
JDK除了在java.lang下提供了4个基本的Annotation之外,还在java.lang.annotation包下提供了4个元 Annotation,这4个元Annotation都用于修饰其他的Annotation定义。

1、@Retention(保留)
@Retention只能用于修饰一个Annotation定义,用于指定被修饰的Annotation可以保留多长时间,@Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention时必须为该value成员变量指定值。
value成员变量的值都是枚举常量,只能是如下3个:
RetentionPolicy.CLASS:编译器将把Annotation记录在class文件中。当运行Java程序时,JVM不再保留Annotation。(默认值)

RetentionPolicy.RUNTIME:编译器将把Annotation记录在calss文件中。当运行Java程序时,JVM也会保留Annotation,程序可以通过反射获取该Annotation信息。

RetentionPolicy.SOURCE:Annotation只保留在源代码中,编译器直接丢弃这种Annotation。

2、@Target(对象,目标)
@Target也只能修饰一个Annotation定义,它用于指定被修饰的Annotation能用于修饰哪些程序单元。@Target元Annotation也包含一个名为value的成员变量,该成员变量的值
只能是如下几个:
ElementType.ANNOTATION_TYPE:注释类型声明

ElementType.CONSTRUCTOR:构造方法声明

ElementType.FIELD:字段声明(包括枚举常量)

ElementType.LOCAL_VARIABLE:局部变量声明

ElementType.METHOD:方法声明

ElementType.PACKAGE:包声明

ElementType.PARAMETER:参数声明

ElementType.TYPE:类、接口(包括注释类型)或枚举声明

3、@Documented(备有证明文件的)
被该元Annotation修饰的Annotation类将可以被javadoc工具提取成文档,从而成为API文档中的一部分。

4、@Inherited(通过继承得到的)
被@Inherited 元 Annotation修饰的Annotation将具有继承性,如某个类使用了@NoName Annotation(该Annotation被@Inherited修饰)修饰,则其子类将自动被@NoName修饰。

四、自定义Annotation,及提取Annotation信息
如下:
//算定义一个Annotation类型
public @interface MyAnnotation{}
它默认是的RetentionPolicy.CLASS,要使用反射提取信息时,必须设置其为RUMTIME。当无@Target修饰时,它该Annotation可以在程序的任何地方使用该Annotation。
例子:
package com.itheiam.blog;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value={ElementType.TYPE,ElementType.ANNOTATION_TYPE})
//设置保留为运行时期。
@Retention(RetentionPolicy.RUNTIME)
//使该Annotation具备继承性。
@Inherited
public @interface MyAnnotation
{

}
@MyAnnotation
class Base
{
}
class InheritableTest extends Base
{
public static void main(String[] args)
{
//当没有使用@Inherited修饰时,输出false。
System.out.println(InheritableTest.class.isAnnotationPresent(MyAnnotation.class));
/*当没有设置@Retention(RetentionPolicy.RUNTIME)为运行时期时,或没有使用@Inherited修饰
下面将看不到任何结果*/
//通过反射的方法判断是否存在自定义的Annotation
if (Base.class.isAnnotationPresent(MyAnnotation.class))
{
MyAnnotation annotation = (MyAnnotation)
Base.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation);
}
System.out.println("-------------------------");
if (InheritableTest.class.isAnnotationPresent(MyAnnotation.class))
{
MyAnnotation annotation = (MyAnnotation)
InheritableTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation);
Annotation[] annotations = MyAnnotation.class.getAnnotations();
System.out.println(annotations);
for (Annotation annotation1 : annotations)
{
System.out.println(annotation1);
}
}
}
}
/*
-----------------------------------
打印结果:
true
@com.itheiam.blog.MyAnnotation()
@com.itheiam.blog.MyAnnotation()
[Ljava.lang.annotation.Annotation;@14d7745
@java.lang.annotation.Target(value=[TYPE, ANNOTATION_TYPE])
@java.lang.annotation.Retention(value=RUNTIME)
@java.lang.annotation.Inherited()
@java.lang.annotation.Target(value=[TYPE, ANNOTATION_TYPE])
-----------------------------------
*/

五、自定义Annotation,带成员变量
根据Annotation是否可以包含成员变量,可以把Annotation分为如下两类。
标记Annotation:一个没有定义成员变量的Annotation类型被称为标记。这种Annotation利用自身的存在与否来为我们提供信息,如前面介绍的@Override、@Test等Annotation。

元数据Annotation:包含成员变量的Annotation,因为它们可以接受更多的元数据,所以也被称为元数据Annotation

示例一:
package com.itheiam.blog;
public @interface MyAnnotationTest
{
//注意它定义的格式
String name();
int age();
}
class Test
{
//必须指定属性,否则会报错
@MyAnnotationTest(age = 3, name = "heima")
public void info(){}
}
示例二:
package com.itheiam.blog;
public @interface MyAnnotationTest
{
//注意它定义的格式
String name() default "noname";
int age() default 0;
}
class Test
{
//因为上面定义时就有了默认值,可以不指定属性,如果指定,则默认值失效
@MyAnnotationTest
public void info(){}
}

六、附注解的应用结构图


--------- android培训java培训、期待与您交流!----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  annotation