注解详细
一、什么是注解?
注解(annotation-也称元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。----------------Thinking in Java书中的第20章
简单地说,注解相当于一种标记,加了注解就等于打上了某种标记,如果你加了标记,那javac(java编译器)或开发工具或其他的程序就可以用反射来了解你的类及类中的各个元素上有没有标记,有什么标记,就去干与标记相关的事。标记可以加在包、类、字段、方法、方法中的参数和局部变量上,可以简单理解为标记可以加在类中所有元素的身上。
二、注解的优点
1.它们可以提供用来完整地描述程序所需的信息,而这些信息是无法用Java来表达的,因此注解使得我们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息。
2.注解是在实际的源代码级别保存所有的信息,而不是某种注释性的文字,这使得代码更整洁,且便于维护。
3.减少配置文件的数量。
三、注解的作用
1.生成文档。这是最常见的,也是java最早提供的注解。常用的有@see,@param,@return等
2.跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。
3.在编译时进行格式检查。如@Override放在方法前,如果你这个方法并不是覆盖了父类(也叫超类)的方法,则编译时就能检查出来。
四、使用注解的情况
1.假如我在写程序时,曾经写了一个方法public static void sayHello(){System.out.println("hi,传智播客");},随着时间的流逝,我要升级程序了,但是发现这个sayHello()方法不怎么好,我不想用了,那怎么办?删了吧,以前用到此方法的地方会报错,不删吧,又怕新来的程序员调用此方法。这时候我们就可以用上注解了,在JavaSE5中内置了三种注解定义在java.lang包中,里面有一个@Deprecated(弃用的意思)的注解,我们只要在sayHello()方法上加上@Deprecated注解就能满足我们的需求了。
代码演示:
没加注解的代码
加了注解的代码
六、注解的应用
1.使用注解
当在程序中调用一个过时的方法时,Eclipse工具会在过时的方法上面画上一跳横线,如图所示。
当你没有用开发工具编译上面的方法,而是用cmd命令行,javac命令编译上面的方法时,会是什么样的呢?如下图所示
然而有些人,就喜欢用过时的方法,并且不希望被提示,那又怎么做呢?这时我们可以在方法前面加一个特殊的标识(也就是注解)代码如下:
@SuppressWarnings("deprecation")//SuppressWarnings压制警告
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
System.runFinalizersOnExit(true);
}
当你在方法前面加上@SuppressWarnings("deprecation ")时,在Eclipse中那条横线还是存在的,但是你用cmd命令行javac编译,就不会有提示了,如图
2.自定义注解
注解就是一个特殊的类,当你要用一类时,不是不要让这个类先存在呀,答案坑定是要的,所以用注解时,也要先有注解。一个注解将会和3个类有联系,下面给张图帮助理解
注解的语法有点类似于接口,只是在接口前面加了一个“@”符号,public @interface ItcastAnnocation {}
定义一个注解
public @interface ItcastAnnocation {
}
在一个类中使用注解
@ItcastAnnocation
public class AnnotationTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//System.runFinalizersOnExit(true);
//sayHello();
/**
*判断注解ItcastAnnocation在不在AnnotationTest类上面
*方法isAnnotationPresent帮助文档的介绍是: 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
*/
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnocation.class)){
System.out.println(1);
ItcastAnnocation itcastAnnocation =( ItcastAnnocation)AnnotationTest.class.getAnnotation(ItcastAnnocation.class);
System.out.println(itcastAnnocation);
}
}
运行结果:控制台不输入任何东西。要想让控制台打印出1和其他的东西,就要先介绍元注解----元注解就是,注解的注解(在注解类身上加的注解)。
然后将注解类改成下面这样
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Retention:保留
* Retention:保留;Policy:政策
* RUNTIME:我的理解是运行时
*/
@Retention(RetentionPolicy.RUNTIME)//这理解为:把ItcastAnnocation注解保留到运行时
public @interface ItcastAnnocation {
}
输出结果:
1
@cn.itcast.day2.ItcastAnnocation()
这里面有这样一些情况:
情况一:一个类被Javac编译成class文件的时候,Javac可能会把这个类上面的注解给去掉,所以当你用class文件的时候就找不到类上面的注解。
情况二:假如Javac没有去掉注解,程序用class文件的时候,会用类加载器把class文件给调到内存里面去,(class文件里面的东西不是字节码,只有类加载器把class文件里面的东西做安全检查等各方面的处理,人后再加载到内存中,这时候的class才是字节码),类加载器也可能会把class文件里面的注解给去掉。
所以说注解的生命周期有3个阶段分别是:java源文件、class文件、内存中的字节码。
@Retention(RetentionPolicy.RUNTIME)中的RetentionPolicy有三种取值RetentionPolicy.SOURCE、RetentionPolicy.CLASS和RetentionPolicy.RUNTIME分别对应上面所说的三个生命周期。默认值在class阶段。
思考题:@Override、@SuppressWarnings、@Deprecated这三个分别在什么阶段?
先看代码:
/**
* Retention:保留
* Retention:保留;Policy:政策
* RUNTIME:我的理解是运行时
* Target:目标
* Element:元素
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//这理解为:把ItcastAnnocation注解保留到运行时
public @interface ItcastAnnocation {
}
下面介绍一个@Target(ElementType.PACKAGE),他也是元注解,他是用来限定注解的位置的,上面是把注解限定在方法上的。所以出现了在使用时如下图的错误,下图是放在类上的
要定义在多个地方都能用要这样写@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PACKAGE}),{}数组的简写。
比class高一级的抽象是Type,接口、枚举、注解它们像类,单严格的说又不是,但它们都表示一个java的类型,class也属于java的类型。所以在@Target()里面要表示类的话得用ElementType.TYPT来表示,TYPE也是jdk1.5才出现的
七、注解的高级运用
一、注解的属性
1、注解的属性与作用
打个比方说:假如你是一个传智播客的学生,为了让别人知道,我就会给你贴上一个标签(在代码中就是注解),但是光贴上标签是不够的,因为我想知道你是哪个班的,但是我无法知道啊,这时候怎么办呢?我们可以用注解的属性来解决这个问题。
2、给注解添加属性代码演示3
添加注解属性
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Retention:保留
* Retention:保留;Policy:政策
* RUNTIME:我的理解是运行时
* Target:目标
* Element:元素
*/
@Target({ElementType.TYPE,ElementType.METHOD,})
@Retention(RetentionPolicy.RUNTIME)//这理解为:把ItcastAnnocation注解保留到运行时
public @interface ItcastAnnocation {
String color() default "blue";//设置color属性的默认值为blue
String value();
int[] arrayAtt();//为注解添加数组类型的属性
EnumLight light();//为注解添加枚举类型的属性
MyMetaAnnotation test1() ;//为注解添加注解类型的属性
Class test2();//为注解添加原始类型的属性
}
使用注解属性
package cn.itcast.day2;@ItcastAnnocation(color="red",value="abc",arrayAtt=3, light = EnumLight.red, test1 = @MyMetaAnnotation("bgv"),test2=int.class)
public class AnnotationTest {
/**
* @param args
*/
// @ItcastAnnocation("abc",arrayAtt = { 0 })
public static void main(String[] args) throws Exception{
/**
*判断注解ItcastAnnocation在不在AnnotationTest类上面
*方法isAnnotationPresent帮助文档的介绍是: 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
*/
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnocation.class)){
ItcastAnnocation itcastAnnocation =( ItcastAnnocation)AnnotationTest.class.getAnnotation(ItcastAnnocation.class);
System.out.println(itcastAnnocation.color());//打印属性color的值
System.out.println(itcastAnnocation.value());//打印属性value的值
System.out.println(itcastAnnocation.arrayAtt().length);//打印数组属性的长度
/**
* 打印数组属性中的每个元素
*/
for (Object obj : itcastAnnocation.arrayAtt()) {
System.out.println(obj);
}
System.out.println(itcastAnnocation.light());//打印枚举属性的值
System.out.println(itcastAnnocation.test1().value());//打印出注解属性类型为注解的注解,它的属性。
System.out.println(itcastAnnocation.test2());//打印原始类型的属性
}
}
}
上面用到的2个类
1.
red,green,yellow;
}
2.
/**
* 用来测试注解属性是注解类型用的
* @author JSON
*
*/
public @interface MyMetaAnnotation {
String value();
}
关于注解属性不带‘=’符号的写法
@SuppressWarnings("deprecation"),如果只有一个属性的值需要你赋值,那么你就可以不写等号了。
---------------------------------------------------------------------------------------------------------------------------------------
public @interface ItcastAnnocation {
String color() default "blue";//default:用法是给color属性设置默认值为blue
String value();
}
运行打印输出:
red
abc
1
3
red
bgv
int
注意的地方:
注解属性方法可以没有任何参数
注解属性方法不能有任何类型的参数
注解属性方法声明不能有一个throws子句
最后更新:2017-04-03 14:54:15