一.注解理解
1、注解,或者叫做注释类型,英文单词是:Annotation
2、注解Annotation是一种引用数据类型。编译之后也是生成xxx.class文件。
3、怎么自定义注解呢?语法格式?
[修饰符列表] @interface 注解类型名{
}
4、注解怎么使用,用在什么地方?
- 第一:注解使用时的语法格式是:
@注解类型名 - 第二:注解可以出现在类上、属性上、方法上、变量上等…
注解还可以出现在注解类型上。
5、JDK内置了哪些注解呢?
java.lang包下的注释类型:
-
掌握:
Deprecated 用 @Deprecated 注释的程序元素,
这个注解主要是向其他程序员传递一个信息,告知已过时,有更好的选择,
不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。 -
掌握:(表示性注解,给编译器参考的)
1. Override 表示一个方法声明打算重写超类中的另一个方法声明。
2. 这个注解只能注解方法,不能注解类,这个注解是给编译器参考的,和运行阶段没有关系。
3. 凡是java中的方法带有这个注解的,编译器都会进行编译检查,如果不是重写父类方法,编译器报错。 -
不用掌握:
SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的
所有程序元素)中取消显示指定的编译器警告。
6、元注解
什么是元注解?
- 用来标注“注解类型”的“注解”,称为元注解。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override{
}
(1)常见的元注解有哪些?
Target
Retention
(2)关于Target注解:
这是一个元注解,用来标注“注解类型”的“注解”
这个Target注解用来标注“被标注的注解”可以出现在哪些位置上。
@Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上。
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
表示该注解可以出现在:
构造方法上
字段上
局部变量上
方法上
....
类上...
(3)关于Retention注解:
这是一个元注解,用来标注“注解类型”的“注解”
这个Retention注解用来标注“被标注的注解”最终保存在哪里。
@Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中。
@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中。
@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制所读取。
7、Retention的源代码
//元注解
public @interface Retention {
//属性
RetentionPolicy value();
}
RetentionPolicy的源代码:(枚举类型)
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
//@Retention(value=RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{}
8、Target的源代码
//元注解
public @interface Target{
//数组
ElementType[] value();
}
ElementType的源代码:(枚举)
public enum ElementType{
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR
}
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface MyAnnotation{}
二.自定义注解
1.自定义属性
//自定义的注解
public @interface MyAnnotation{
String name();
//颜色属性
String color();
int age() default 25; //属性指定默认值
}
//测试注解
public class MyAnnotationTest{
//报错原因:如果一个注解当中有属性,那么必须给属性赋值(除非有默认值)
//@MyAnnotation(属性名=属性值)
@MyAnnotation(name = "zhangsan",color = "红色")
public void doSome(){
}
}
如果一个属性的名为value的时候,并且注解只有一个属性的时候,使用注解时可以省略赋值名 “hahaha”
public @interface MyAnnotation{
String value();
}
@MyAnnotation("hahaha")
public void doSome(){
}
注解当中的属性可以是哪一种类型
- 属性的类型可以是:
byte short int Long float double boolean char String Class 枚举类型
以及以上的每一种的数组形式。
public @interface OtherAnnotation {
//年龄属性
int age();
//邮箱地址属性,支持多个
String[] email();
//季节数组,Season枚举类型
Season[] seasonArray();
}
public class OtherAnnotationTest{
//数组是大括号
@OtherAnnotation(age = 25,email = {"zhangsan@123.com","zhangsan@sohu.com"},seasonArray = Season.WINTER)
public void doSome(){}
//如果数组中只有一个元素:大括号可以省略。
@OtherAnnotation(age = 25,email = "zhangsan@123.com",seasonArray = {Season.SPRING,Season.SUMMER})
public void doOther(){}
}
2.反射注解
注解类
public class ReflectAnnotationTest{
public static void main(String[] args) throws Exception{
//获取这个类
Class c = Class.forName("com.tx.java.annotation.MyAnnotationTest");
//判断类上上面是否有@MyAnnotation
//System.out.println(c.isAnnotationPresent(MyAnnotation.class)); //true
if(c.isAnnotationPresent(MyAnnotation.class)){
//获取该注解对象
MyAnnotation myAnnotation = (MyAnnotation)c.getAnnotation(MyAnnotation.class);
//System.out.println("类上面的注解对象"+myAnnotation);//@com.tx.java.annotation
//获取注解对象的属性。
String value = muyAnnotation.value();
System.out.println(value); //北京新区
}
//判断String类上面是否存在这个注解
Class stringClass = Class.forName("java.lang.String');
System.out.println(stringClass.isAnnotationPresent(MyAnnotation.class)); //false
}
}
@MyAnnotation("北京新区")
public class MyAnnotationTest{
}
注解方法
public class MyAnnotationTest{
@MyAnnotation(username = "admin",password = "456456")
public void doSome(){
}
public static void main(String[] args) throws Exception{
//获取MyAnnotationTest的doSome()方法上面的注解信息。
Class c = Class.forName("com.tx.java.annotation.MyAnnotationTest");
//获取doSome()方法
Method doSomeMethod = c.getDeclaredMethod("doSome");
//判断该方法是否存在这个注解
if(doSomeMethod.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation myAnnotation = doSomeMethod.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.username());
System.out.println(myAnnotation.password());
}
}
}
三.注解在开发中有什么用呢?
需求:
假设有这样一个注解,叫做:@Id
这个注解只能出现在类上面,当这个类上有这个注解的时候,
要求这个类中必须有一个int类型的id属性。如果没有这个属性
就报异常。如果有这个属性则正常执行!
//获取类
Class userClass = Class.forName("com.tx.java.annotation.User");
//判断这个类中是否存在Id注解
if(userclass.isAnnotationPresent(Id.class)){
//当一个类上面有@Id注解的时候,要求类中必须存在int类型的id属性
//如果没有int类型的id属性则报异常。
//获取类的属性
Field[] fields = userClass.getDeclaredFields();
boolean isOk = false;//给一个默认标记
for(Field field : fields){
if("id".equals(field.getName())&&"int".equals(field.getType().getSimpleName())){
//表示这个类是合法的类,有@Id注解,则这个类中必须有int类型的id
isOk = true; //表示合法
break;
}
}
//判断是否合法
if(!isOk){
throw new HasNotIdPropertyException("被@Id注解标注的类中必须要有一个int类型的id属性");
}
}