注解就是一种注释类型,它是一种引用型数据类型,编译之后也是class文件
注解的语法格式是:
[访问修饰符] @interface 注解类型名{
}
public @interface MyAnnotation {
}
注解的作用:
- 注解使用的语法格式是:@注解名
- 注解可以出现在类、属性、方法、变量上等。。。
- 注解也可以出现在注解上
package com.kongxiao.javase.annotation;
@MyAnnotation
public class AnnotationTest01 {
// 变量
@MyAnnotation
private int a ;
@MyAnnotation
private String b ;
// 构造方法和形参
@MyAnnotation
public AnnotationTest01(@MyAnnotation int a, @MyAnnotation String b) {
this.a = a;
this.b = b;
}
@MyAnnotation
public AnnotationTest01() {
}
// 实例方法
@MyAnnotation
public void doSome(){
// 局部变量
@MyAnnotation
int temp = 10;
System.out.println("test");
}
}
// 接口
@MyAnnotation
interface TestInterface{
}
// 枚举
@MyAnnotation
enum Season {
@MyAnnotation
SPRING,SUMMER,AUTUMN,WINTER
}
@Override
注解
- @Override只能注解方法
- @Override这个注解是编译器参考的,和运行阶段没有关系。
- 表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
public class Test01 {
private int no;
private String name;
@Override
public String toString() {
return "Test01{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
Override注解上还有两个元注解:
指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE,
/**
* Module declaration.
*
* @since 9
*/
MODULE
}
指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS
。
只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
注:RUNTIME表示保存到源文件中,并且可以被反射机制反射到。
@Deprecated
注解
用 @Deprecated
注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。
注解中属性的定义方法
public @interface MyAnnotation {
/**
* 属性的定义方法
*/
String name();
}
如果一个注解中有属性,那么必须给属性赋值
public class AnnotationTest03 {
/*如果一个注解中有属性,那么必须给属性赋值
@MyAnnotation
public void doSome(){
}*/
//@MyAnnotation(属性名 = 值)
@MyAnnotation(name = "SUN")
public void doSome1(){
}
}
可以用default指定
public @interface Deprecated {
/**
* Returns the version in which the annotated element became deprecated.
* The version string is in the same format and namespace as the value of
* the {@code @since} javadoc tag. The default value is the empty
* string.
*
* @return the version string
* @since 9
*/
String since() default "";
/**
* Indicates whether the annotated element is subject to removal in a
* future version. The default value is {@code false}.
*
* @return whether the element is subject to removal
* @since 9
*/
boolean forRemoval() default false;
}
属性是value时并且只有一个属性时,value可以省略
public @interface MyAnnotation {
/**
* 属性是value
*/
String value();
}
public class AnnotationTest04 {
/*报错:如果一个注解中有属性,那么必须给属性赋值
@MyAnnotation()
public void doSome(){
}*/
//@MyAnnotation(值)
@MyAnnotation("SUN")
public void doSome1(){
}
}
属性的类型
可以是 byte ,short,int ,long,float,double,boolean,char,String,Class ,枚举类型以及它们的数组形式,其它的都不行。
注解在开发中有什么用
需求:
假设有这样一个注解: @ID
这个注解只能出现类上,当这个类上有这个注解时,要求这个类中必须有一个int类型的id属性,没有就会报错。
注解定义:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {
}
被@ID注解的类User:
@ID
public class User {
//int id;
String name;
String passWord;
}
Test类:
import java.lang.reflect.Field;
public class ClassTest {
public static void main(String[] args) throws Exception {
Class userClass = Class.forName("com.kongxiao.javase.annotation.User");
if (userClass.isAnnotationPresent(ID.class)){
Field [] fields = userClass.getDeclaredFields();
// 默没有id属性
boolean b = false;
for(Field field:fields){
if("id".equals(field.getName())&&"int".equals(field.getType().getSimpleName())){
b = true;
break;
}
}
if(!b){
throw new MeiYouHahahaException("被 @ID 注解的类中必须包含一个 int 类型的 id 属性!");
}
}
}
}
自定义异常类:
public class MeiYouHahahaException extends RuntimeException {
public MeiYouHahahaException (){
super();
}
public MeiYouHahahaException(String message){
super(message);
}
}
输出:
D:\Java\jdk-12.0.2\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=62250:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath G:\JavaXB\out\production\Annotation com.kongxiao.javase.annotation.ClassTest
Exception in thread "main" com.kongxiao.javase.annotation.MeiYouHahahaException: 被 @ID 注解的类中必须包含一个 int 类型的 id 属性!
at com.kongxiao.javase.annotation.ClassTest.main(ClassTest.java:26)
Process finished with exit code 1