一.前言
我的前一篇文章主要说了,注解的格式,注解的一些的基础东西。
java注解基础(一)
本篇文章主要说明注解中的属性,常用的元注解,以及注解的一些细节。
注解可能会在类上,方法上,类的属性(即成员变量)上使用。
二.注解的属性
在java的接口中,有常量,还有public abstract的抽象方法。
注解本质上也是接口,而属性也就是接口中的抽象方法,但不同之处在于,接口中的属性有特定的返回值类型。
返回值类型有以下几种:
1.基本数据类型
2.String字符串类型
3.枚举类型
4.注解类型
5.以上类型的数组
接下来说说怎么使用属性。
我们先来自定义一个注解。
//这个是我们的一个注解,
//而且定义了一个属性
public @interface MyAnno {
int show();
}
然后我们来使用它,使用格式 “@+注解名称”.
//使用注解
@MyAnno(show = 1)
public class TestAnno{
}
这里是使用了注解,并且给注解定义的属性,它的定义形式很像变量,所以叫它属性。
下面演示其他类型的属性的使用。
我们来重新定义一个注解
//里面包含了一些上述所说到的属性的类型
public @interface MyAnno1{
int number();
String string();
Person person();
MyAnno myAnno();
}
//里面的Person是枚举类型,定义如下
public enum Person{
P1,P2;
}
下面我们来使用这个注解
// 注解的使用
@MyAnno1(number = 1,string = "2",person = Person.P1,myAnno = @MyAnno(1))
public class TestAnno{
}
这里没有给出全部基础类型的用法,类比int的用法即可。
再说说数组类型的
重新定义注解MyAnno1
// 重新定义MyAnno1
public @interface MyAnno1{
String[] string();
}
我们来使用它
// 使用注解
@MyAnno1(string = {"1","2"})
public class TestAnno{
}
//特殊使用,数组只有一个值的时候
@MyAnno1(string = "1")
public class TestAnno{
}
要是属性是数组类型的时候,多个值,用大括号括起来,用逗号分开。
如果只有一个值的特殊情况的时候,跟String方式赋值一样即可。
属性要注意的地方:
1)属性中只有value命名的时候可以省略赋值
我们新定义一个注解
public @interface MyAnno2 {
int value();
}
我们来使用它
@MyAnno2(1)
public class Test{
}
就像上述的一样。
2)属性中也可以设置默认值用关键字default
我们重新定义MyAnno1注解
public @interface MyAnno2 {
int value() defalut 1;
}
有默认值的话,就可以这样定义,也可以加入数字。
@MyAnno2()
public class TestAnno {
}
三.元注解
上面我们说完了注解的属性,接下来我们说说注解的组成的另一部分,元注解,我这里只是介绍常用的元注解跟用法。
注意:元注解都是在注解的定义上使用的。
在其他地方定义会报错。
我们来了解一下什么是元注解。元注解:用于描述注解的注解。
这一行可能不太理解,没关系,我们来往下看一点一点理解。
常用的元注解有这么几种,@Target,@Retention,@Documented,@Inherited这四种下面我们来一一介绍。
@Target:描述注解能够作用的位置
- ElementType取值:
- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
我们来看一个例子
// @Target举例
@Targer(ElementType.Type)
public @interface MyAnno3{
}
我们把MyAnno3注解设置为上述形式,来使用它。
//测试MyAnno3
@MyAnno3()
public class TestAnno{
//@MyAnno3
String str;
//@MyAnno3
public void show(){}
}
我为什么要在属性跟方法上的注解加上注释呢,因为会报错啊。
我们已经设置了@Target只能作用在类上了,所以在成员变量跟方法上的使用会报错。
我们来看一下ElementType的定义
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE
}
可以看到ElementType是个enum类型,即枚举类型。
而Target的定义
public @interface Target {
ElementType[] value();
}
参数中有一个ElementType数组,就是说可以给多个值,而且属性命名为value,也就是说可以省略。
@Target的使用讲解告一段落。
下面我们来说说@Retention,@Retention:描述注解被保留的阶段.
它有一下三种常用应用,我这里只是做个大概的描述。
- @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到(常用)
- @Retention(RetentionPolicy.CLASS):当前被描述的注解,会保留到class字节码文件中
- @Retention(RetentionPolicy.SOURCE): 当前被描述的注解,无动作
看看他的源码
public @interface Retention {
RetentionPolicy value();
}
可以看到熟悉的value命名,只有一个的RetentionPolicy 类型。
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
可以看到RetentionPolicy 也是enum枚举类型。
最后两种注解就简单介绍一下。
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承
比如Person类上有个@MyAnno的注解 MyAnno注解中有定义了@Inherited
那在继承Person时候MyAnno也过来了
使用一下他们。
@Documented
@Inherited
public @interface MyAnno4{}
四.JDK中的常用注解
这里列举了一些常用的JDK中预定义的一些注解,当做了解。
@Override :检测被该注解标注的方法是否是继承自父类(接口)的
看源码可知,Override是只能用在方法上的。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Deprecated:该注解标注的内容,表示已过时 但是可以用 用于版本兼容
表示为一个横杠。
举个例子,我这样定义了一个变量
@Deprecated
static String string = "0";
效果图如下,会出现一条横线。
我们再来看一下源码,可见它在哪都能用(根据@Target注解得知的)。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@SuppressWarnings:压制警告
一般传递参数all @SuppressWarnings(“all”)
知道他是干什么的了,看看源码先。
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
可见他也是在哪都能用(根据@Target注解得知的),还有就是让需要一些String类型的参数。这里就不过多描述了。
五.总结
这篇文章主要介绍了,注解的属性,常用的元注解以及常用的JDK预定义的注解,简单看了看他们的源码,希望读者有所收获。