Java注解数据类型

1.注解的定义

注解:或者叫做注释类型,英文单词是Annotation(不是//或者/**/)
注解Annotation是一种引用数据类型。编译之后也是xxx.class文件
怎么定义自己的注解呢?语法格式如下:

[修饰符列表] @interface 注解类型名{
    
}

2.注解的使用

2.1使用时的语法格式

@注解类型名:@Override

注解可以出现在类上,属性上,方法上,变量上…

注解还可以出现在注解类型上。

@MyAnnotation
public class AnnotationTest01 {
    @MyAnnotation
    private int no;

    public AnnotationTest01() {
    }

    public static void m1(){
        @MyAnnotation
        int i = 0;
    }
    public void m2(@MyAnnotation String name){

    }
}
@MyAnnotation
public @interface OtherAnnotation {
}

2.2 JDK中的内置注解

Java后台验证注解支持的类型 java注解支持的数据类型_System

2.2.1 Override注解

@Override这个注解只能注解方法

@Override是给编译器参考的,和运行阶段没有关系

凡是java中带有这个注解的,编译器都会进行检查,假如不是重写父类的方法,那么会报错

这个注解只是在编译期有作用,和运行期无关。

/*
关于JDK lang包下的Override注解
源代码:
public @interface Override{
}
 */
//@Override
public class AnnotationTest02 {

    @Override
    public String toString() {
        return "AnnotationTest02{}";
    }
}

2.2.2 元注解

什么是元注解?

用来标准注解类型的注解称为“元注解”

常见的元注解有哪些?

  • Target
  • Retention
2.2.2.1关于Target注解

这是一个元注解,用来标注“注解类型”的注解

这个Target注解用来标注“被标注的注解”可以出现在哪些位置上

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Target(ElementType.METHOD)表明注解只能出现在方法上

2.2.2.2关于Retention注解

Rentention:这是一个元注解,表示“被标注的注解”最终保存到哪里

@Retention(RetentionPolicy.SOURCE):表示该注解只保存在java源文件中

@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中

@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,且可以被反射机制获取

2.2.3 Deprecated注解

Deprecated这个注解表明被标注的元素已经过时

这个注解向其他程序员传达一个信息:告知已过时,有更好的解决方法存在。

//表示这个类已经过时
@Deprecated
public class AnnotationTest03 {
    @Deprecated
    public static void doSome(){
        System.out.println("do something!");
    }

    public static void doOther(){
        System.out.println("do other....");
    }
}

class T {
    public static void main(String[] args) {
        AnnotationTest03 annotationTest03 = new AnnotationTest03();
        AnnotationTest03.doSome();
        AnnotationTest03.doOther();
    }
}

2.3 自定义注解

2.3.1 属性值

/*
自定义注解:MyAnnotation
 */
public @interface MyAnnotation {
    /**
     * 我们通常在注解中可以定义属性,以下这个是MyAnnotation的name属性
     * 看着是一个方法,实际上是一个属性
     */
    String name();
}

当注解中定义了属性之后,之后在需要的地方写注解时就要加上属性值:@MyAnnotatioon(name = "张山"),否则会报错。除非这个属性有defult默认值。示例代码如下:

/*
自定义注解:MyAnnotation
 */
public @interface MyAnnotation {
    /**
     * 我们通常在注解中可以定义属性,以下这个是MyAnnotation的name属性
     * 看着是一个方法,实际上是一个属性
     */
    String name();
    
    /*
    颜色属性
     */
    String color();
    
    /*
    注解还可以默认,默认的注解不写值也行
     */
    int age() default 25;
}
public class AnnotationTest01 {
    private int no;
    @MyAnnotation(name = "张三",color = "红色")
    public AnnotationTest01() {
    }
    public static void m1(){
        int i = 0;
    }
    public void m2(String name){

    }
}

2.3.2 属性值为value

当属性值为value,且只有这一个属性时,属性名可以省略,其他的属性名不行:

public @interface MyAnnotation2 {
    String value();
    //String name;
}
public class MyAnnotationTest {
    //报错原因:注解为赋属性值
//    @MyAnnotation2
//    public void doSome(){
//
//    }
    @MyAnnotation2(value = "hahaha")
    public void doSme(){

    }

    @MyAnnotation2("yiyiyi~~")
    public void doOther(){

    }
}

2.3.1属性的类型

注解中的属性可以是哪一种类型?
可以是一下的所有,以及每一种类型的数组:
byte short int long float double boolean char
String Class

public @interface MyAnnotation3 {
    /*
    注解中的属性可以是哪一种类型?
    可以是一下的所有,以及每一种类型的数组:
        byte short int long float double boolean char
        String Class
     */
    String[] myString();
    int value1();

    Class parameterType();

    Class parameterTypes();

    Season season();
    
    Season[] seasons();
}
  • 数组形式的 { } 的省略
public @interface OtherAnnotation2 {
    //年龄属性
    int age();

    /*
     * 邮箱地址属性,支持多个
     */
    String[] email();

    Season[] season();

}
public class OtherAnnotation2Test {
    @OtherAnnotation2(age = 25, email = {"2232143462@qq.com","lisi@qq.com"},season = Season.AUTUMN)
    public void doSome(){

    }

    //如果数组中只有一个元素,那么{}可以省略
    @OtherAnnotation2(age = 2,email = "Blanche@qq.com",season = {Season.SPRING,Season.SUMMER,Season.WINTER})
    public void doOther(){

    }

}

2.4 反射机制获取注解

  • 注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//只允许注解标注类和方法
@Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE,ElementType.FIELD,ElementType.METHOD})
//希望这个注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation5 {
    String address() default "北极";
}
  • 被测试类
@MyAnnotation5
public class MyAnnotationTest4 {
    @MyAnnotation5
    int i;

    @MyAnnotation5
    public void doSome(){

    }

}
  • 测试类
    通过反射机制获取注解
public class ReflectAnnotationTest {
    public static void main(String[] args) throws Exception{
        //获取类
        Class c = Class.forName("MyAnnotationTest4");
        //判断类上是否有Annotation
        //System.out.println(c.isAnnotationPresent(MyAnnotation5.class));
        if(c.isAnnotationPresent(MyAnnotation5.class)){
            MyAnnotation5 myAnnotation5 = (MyAnnotation5) c.getAnnotation(MyAnnotation5.class);
            System.out.println("类上的注解:" + myAnnotation5);

            //要获取注解对象的属性怎么办?和调接口一样
            String address = myAnnotation5.address();
            System.out.println(address);
        }

        //判断String类上是否有这个注解
        Class str = Class.forName("java.lang.String");
        System.out.println(str.isAnnotationPresent(MyAnnotation5.class));
    }
}

3.注解的作用

需求:假设有这样的一个注解,叫做@id

这个注解只能出现在类上面,当一个类上面有这个注解的时候,这个类中必须有一个int类型的id属性,否则就报异常

如果有这个属性,就正常执行。

  • 注解类
package AnnatationExample;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Id {

}

//这个注解用来标注类,被标注的类必须有一个int类型的id属性,否则报异常
package AnnatationExample;
@Id
public class User {
    int id;
    String name;


}
  • 测试类
package AnnatationExample;

import java.lang.reflect.Field;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取类
        Class userClass = Class.forName("AnnatationExample.User");
        boolean flag = false;//默认的标记,默认值是false;
        //判断类上是否存在Id注解
        if(userClass.isAnnotationPresent(Id.class)){
            //当一个类上有Id注解的时候要求类中必须存在int类型的id属性,否则报异常
            Field[] fields = userClass.getDeclaredFields();
            for(Field field:fields){
                if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
                    //表示是一个正确的类
                    flag = true;
                    break;
                }
            }
        }
        if(!flag){
            throw new HaventIDPropertyException("被Id注解标注的类中必须有一个int类型的id属性!");
        }
    }
}
  • 异常类
package AnnatationExample;

public class HaventIDPropertyException extends RuntimeException{
    public HaventIDPropertyException(){

    }

    public HaventIDPropertyException(String s){
        super(s);
    }

}
break;
            }
        }
    }
    if(!flag){
        throw new HaventIDPropertyException("被Id注解标注的类中必须有一个int类型的id属性!");
    }
}

}

- 异常类

```java
package AnnatationExample;

public class HaventIDPropertyException extends RuntimeException{
    public HaventIDPropertyException(){

    }

    public HaventIDPropertyException(String s){
        super(s);
    }

}