Java注解

类:要给一个类增强一些功能?继承、实现一个接口

class A extend B{}
class A implements C{}

还可以使用注解,增强类或一些方法、属性的功能。

Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。

1. 内置注解

1.1 @Override

确保重写的方法的确存在于父类或接口中,可以避免子类重写父类方法时拼错单词。

public class Father {
	public void eat() {
		System.out.println("Father eat...");
	}
}

class Son extends Father{
	@Override
	public void eat() {
		System.out.println("Son eat...");
	}
}

1.2 @Deprecated

用于给提示,该方法由于安全、性能问题等,已经不推荐使用了。

此外,在版本升级时,如果要计划删除一些方法,也通常会在前一个版本中,将该方法加上@Deprecated,然后在后续版本内删除。

new Thread().stop() // stop处有删除线

1.3 @SuppressWarnings(value=“”)

压制警告(不建议使用)

# value的取值
unchecked = 忽略对泛型类型的检查
deprecation = 忽略一些过期的api
unused = 是否未被使用
fallthrough = switch 是否一直往下执行,而没有break
path = 忽略对路径不存在的检查
serialVersionUID = 忽略一个类可以序列化、但却没有序列化的警告

all = 忽略全部警告
@SuppressWarnings(value = "unchecked")
public class Father {
	private void sysout() {
		// TODO Auto-generated method stub

	}
}

2. 自定义注解

注解的属性也叫做成员变量。注解只有成员变量,没有方法。

注解中属性可以有默认值,默认值需要用 default 关键值指定

用定义方法的形式定义一个属性,方法的名字时属性的名字,方法的返回值就是属性的类型。

public @interface MyAnnotation {
	String[] value() default "张三";// 定义了一个属性
	int age() default 22;
}
public @interface MyAnnotation {
	String[] value() default "张三";// 定义了一个属性
	int age() default 22;
}

class Main{
    // 如果属性唯一可以不用写属性名
	@MyAnnotation(value="李四", age=33)
	public void test() {
		
	}
}

3. 元注解

元数据:修饰数据的数据

元注解:修饰注解的注解

3.1 @Target

限制注解能被使用到哪些元素上(属性、方法、类);

如果一个注解没有@Target描述,则该注解可以修饰任何类型的元素;

如果有@Target修饰,那么该注解只能用于被@Target注解的地方

ElementType.ANNOTATION_TYPE

可以给一个注解进行注解

ElementType.CONSTRUCTOR

可以给构造方法进行注解

ElementType.FIELD

可以给属性进行注解

ElementType.LOCAL_VARIABLE

可以给局部变量进行注解

ElementType.METHOD

可以给方法进行注解

ElementType.PACKAGE

可以给一个包进行注解

ElementType.PARAMETER

可以给一个方法内的参数进行注解

ElementType.TYPE_USE

能标注任何类型的名称

ElementType.TYPE_PARAMETER

对普通变量的声明

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

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String[] value() default "张三";// 定义了一个属性
    int age() default 22;
}

3.2 @Retention

限制注解的生命周期

RetentionPolicy.SOURCE

注解仅存在于源码中,在class字节码文件中不包含

RetentionPolicy.CLASS

默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

RetentionPolicy.RUNTIME

注解会在class字节码文件中存在,在运行时可以通过反射获取到

如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME)

3.3 @Document

javadoc:java帮助文档里默认情况下,是没有对注解的描述的。

它的作用是能够将注解中的元素包含到 Javadoc 中去。

ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

import java.lang.annotation.*;

@Documented
public @interface MyAnnotation {

}

以上注解,会在生成javadoc时,被显示在文档中。

3.4 @Inherited

不是说注解本身会继承,而是指如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

3.5 @Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

4. 自定义注解如何使用?

结合反射使用。

注解以及反射什么时候会真正使用?

开发自己的框架时,在框架的底层,基本上都是注解和反射。

import java.lang.annotation.Annotation;
import java.util.Arrays;

public class MyAnnotationTest {
    @MyAnnotation(value="李四", age=33)
    @Deprecated
    public static void test() throws ClassNotFoundException, NoSuchMethodException, SecurityException {
        Annotation[] a =  Class.forName("MyAnnotationTest").getMethod("test").getAnnotations();

        for (Annotation item : a ) {
            if (item instanceof MyAnnotation) { // @MyAnnotation(value="李四", age=33)
                System.out.println(Arrays.toString(((MyAnnotation) item).value()));
				System.out.println(((MyAnnotation)item).age());
            } else { // @Deprecated
                System.out.println(item);
            }
        }
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
        test();
    }
}