您的位置:首页 > 其它

SE高阶(12):Annotation(注解)的简单了解和使用

2017-04-28 00:26 267 查看

(一)Annotation(注解)的作用

注解的作用是修饰编程元素。编程元素就是:包、类、构造方法、方法、成员变量等。Annotation能对这些元素进行标识,JVM在执行时可以读取标识并执行相应处理。

注解和注释是不同的,区别:注解可以在源文件中加入一些信息,例如使用框架开发时,我们都是通过配置文件进行对象关系组合映射等功能,而通过注解就可以代替配置文件的编写,而注释是开发人员用于方便阅读源代码,不会对程序产生任何影响。总结一句话:注解给JVM看,注释给开发人员看。

注解的基本功能

编写文档:通过代码里标识的元数据生成文档。
代码分析:通过代码里标识的元数据对代码进行分析。
编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。

(二)Java内置注解

Java内置注解是JDK提供的普通注解,在eclipse中可以通过输入@ + alt+/来查看内置注解。除了之外,我们还可以自定义注解,以便用于不同情况。

常用的内置注解:

@Override(重写):标示该方法重写了超类方法或实现了接口类方法;
@Deprecated(弃用、不赞成):表示修饰的方法已被弃用,不赞成使用;
@SuppressWarnings(抑制警告) :让编译器取消警告提醒(即感叹号信息);
@FunctionalInterface(函数接口):Java8新增注解,修饰接口表明只能存在一个抽象方法,但是允许存在多个默认方法;
@SafeVarargs(heap pollution):修饰出现堆污染的情况,如可变形参、泛型数组。
//测试常用的内置注解
public class Test00 extends supClass implements SupImp{
@Override
public void testMethod() { System.out.println("~~~~~~~~"); }
@Override
public void method2() {}//该方法没重写超类方法或实现接口方法,检查报错
@Override
public void impAbc() {}//标识该方法实现了接口方法
}
class supClass{
@Deprecated//修饰的方法会被划横线,表示不赞成使用
public void testMethod(){}
}
@FunctionalInterface
interface SupImp{
void impAbc();
//	void impAbc2();//接口中抽象方法超过一个就会报错
}


(三)元注解

注解分为普通注解和元注解,两者区别:普通注解就是JDK提供的基本注解和自定义的注解,只能注解代码;元注解是修饰注解的注解。使用eclipse可以通过F3查看Java的内置注解的源代码,修饰该注解的注解就是要了解的元注解了。

Java目前提供的元注解如下:

@Documented:修饰的注解可以被Javadoc工具提取成文档;
@Inherited:修饰的注解具有继承性,被修饰的注解修饰一个普通类,该类的子类可以继承父类的注解;
@Repeatable(Java8新增):标识某个注解可以重复使用,但需要一个容器注解的Class实例;(重复注解:允许某个注解可重复使用)
@Target:修饰的注解会被限制使用范围,表示该注解可以用在什么地方,ElementType参数如下:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明
@Retention:表示在什么级别保存该注解信息,修饰的注解具有生命周期。RetentionPolicy参数如下:
SOURCE:注解只保留在源代码中(xx.java),会被编译器直接丢弃
CLASS:注解保留在class文件中,运行时会被JVM丢弃,不可获取信息。作为默认值。
RUNTIME:JVM运行时保留该注解,因此可以通过反射机制读取注解的信息。

@Documented案例

@Documented//该注解能被提取成文档
@Retention(RetentionPolicy.RUNTIME)
@interface AnnoDocu {}
public class TestMetaAnno {
@AnnoDocu
public String str;
@AnnoDocu
public int num;
@AnnoDocu
public void method1() {
}
}
使用Javadoc工具提取TestMetaAnno类,@AnnoDocu注解也会被提取到文档中。要注意javadoc 只能为 public和 protected 成员处理注释文档。



@Inherited案例

@Inherited//修饰的注解允许被继承
@Retention(RetentionPolicy.RUNTIME)//保留到运行时
@interface AnnoInher {}

@AnnoInher
class Father{
}
public class Son extends Father{
public static void main(String[] args) throws Exception {
//获取Son类中所有注解,包括父类的。getDeclared只作用于本身,得不到父类注解
Annotation[] an = Son.class.getAnnotations();
//把该注解数组转成字符串
System.out.println(Arrays.toString(an));
//判断指定的注解是否在Son.class实例对应的类中
System.out.println(Son.class.isAnnotationPresent(AnnoInher.class));
}
}

@Rentention案例

//如果普通注解没使用@Retention,默认使用CLASS。所以自定义注解时最好使用RUNTIME
@Retention(RetentionPolicy.SOURCE)//保留到源代码中(.java),编译期间就被丢弃
@Retention(RetentionPolicy.CLASS)//保留到类文件中(.class),运行时被JVM丢弃
@Retention(RetentionPolicy.RUNTIME)//保留到运行时
@interface RetentionTest {
}


@Target案例

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//限制该注解只能用于类、接口、枚举
@interface TargetTest {}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)//限制该注解只能用于构造器
@interface TargetTest2 {}
//其他参数就不一一演示,使用方式都一样
@TargetTest
public class TestMetaAnno {
@TargetTest2
public TestMetaAnno() {}
}


@Repeatable案例

该注解是Java8新增的,使重复注解看起来更加简洁明了。下面有对比代码:

//Java8之前的重复注解方式,使用一个注解来存储另一个注解
@Retention(RetentionPolicy.RUNTIME)
@interface Books{
Book[] value();//用数组存储@Book注解
}
@interface Book{
String value();
}
//如果注解数量多,可读性会很差,写起来很麻烦
@Books({@Book("A"), @Book("B")})
public class TestMetaAnno {
}


//Java8新特性:@Repeatable
@interface Books{
Book[] value();
}
@Repeatable(Books.class)//标识该注解可重复使用,以@Books作为容器注解存储@Book
@interface Book{
String str();
}
public class TestMetaAnno {
//逻辑清晰,可读性很高
@Book(str = "A")
@Book(str = "B")
@Book(str = "C")
public void method() {System.out.println("~~~~");}
}


(四)自定义注解

自定义注解看起来和接口的定义方式差不多,以@interface作为标识。自定义注解与JDK提供的普通注解并无两样,都可以用于修饰任何程序元素。注解中还可以声明成员变量。
//自定义注解
public @interface MyAnno {
}


//给注解定义成员变量
public @interface MyAnno {
String value();
String
4000
str();
int num();
}

使用说明:注解中定义成员变量方式看起来和接口中的抽象方法差不多。但在注解中,返回值是变量类型,方法名是变量名,不允许传入参数。如果只定义了成员变量,并且变量名是value,则可以直接赋值。例如元注解@Retention(RetentionPolicy.RUNTIME)。

自定义注解使用案例

@MyAnno //注解类
public class AnnoTest {
@MyAnno//注解方法
public void method00() {
System.out.println("======");
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Class cla = AnnoTest.class;
Method me = cla.getMethod("method00");
Annotation[] anCl = cla.getAnnotations();//获取类的所有注解
Annotation[] anMe = me.getAnnotations();//获取指定Method对象的所有注解
for(Annotation a : anCl)
System.out.println("类中的注解:" + a); //没有注解可输出
for(Annotation a : anMe)
System.out.println("Method实例中的注解:" + a.toString());
}
}


使用说明:输出结果会发现没有获取到注解信息,这是因为注解的生命周期默认都是保存在class文件中,运行时就丢弃了,所以获取不了,想要通过反射得到注解信息就需要使用元注解@Retention来修饰普通注解,例如@Rentention(RetentionPolicy.RUNTIME)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息