Java 注解

注解语法

注解的定义

public @interface Text {
}

上方就是一个简单的注解,通过@interface 进行定义,他的定义跟接口很相似,比接口多了一个@符号,上方代码表示定义了一个Text的注解

注解的应用

@Text
public class Annotation {
    public static void main(String[] args) {
    }
}

直接在一个类上加上@Text 就可以使用,不过想要注解正常工作,需要理解元注解

元注解

元注解是可以注解到注解上的注解,元注解是一种基本注解,他可以应用到其他注解上

元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

@Retention
当@Retention应用到注解上的时候,他解释了注解的存活时间

他的取值如下:

RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

下面这段代码指定了运行期间可以获取,所以他的生命周期很长

@Retention(RetentionPolicy.RUNTIME)
@interface Text {
}

@Documented
这个元注解和文档有关,他的作用是可以把元注解中的元素包含到JavaDoc中

@Target

他指定了注解运用的地方,如果没有被@Target注解,那么他可以注解到任何地方,一旦一个注解被@Target注解后,这个注解就限定了应用场景,比如:

ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

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

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}


@Test
public class A {}


public class B extends A {}

@Text 注解被Inherited注解,A被@Text注解,B继承自A,但是B没有注解,B可以继承A的注解@Text

@Repeatable
@Repeatable是1.8之后加入的,是可重复的意思

@interface Persons {
	Person[]  value();
}


@Repeatable(Persons.class)
@interface Person{
	String role default "";
}


@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
	
}

@Repeatable注解了Person,@Repeatable后面括号中的类相当于一个容器注解

什么是容器注解?就是存放其他注解的地方,它本身也是一个注解

@interface Persons {
	Person[]  value();
}

按照规定他,他必须有一个value属性,属性值是,被@Repeatable注解过的注解数组

注解的属性
也叫做注解的成员变量,注解只有成员变量,没有方法,注解的成员变量,在注解中以“无参方法”来声明,其方法名定义了变量的名字,其返回值定义了变量的类型

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface Text {
    int id();
    
    String message();
}

这个注解有俩个属性id和message,在使用的时候我们应该给他们赋值

@Text(id = 1, message = "aa")
public class Annotation {
    public static void main(String[] args) {
    }
}

注解中定义属性的类型

所有基本类型(int,float,boolean,byte,double,char,long,short)

String

Class

enum

Annotation

上述类型的数组

注解中可以有默认值,默认值需要用default关键字定义

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface Text {
    int id() default -1;

    String message() default "";
}

因为又默认值的存在,那么注解可以不用赋值,直接用默认值

@Text
public class Annotation {
    public static void main(String[] args) {
    }
}

快捷方式
当注解中只有一个value属性时,应用这个注解时,可以直接把属性写在括号里

@interface Check {
    String value();
}

@Check("q")
public class A {
}

当一个注解没有任何属性的时候括号都可以省略

注解属性必须要有确定的值,如果没有默认值,那么必须赋值,不管默认值或者赋值,都不能用null来赋值

Java的预制注解

java 本身已经实现的注解

@Deprecated

这个注解是用来标记已经过时的元素的,我们平时开发中应该总会遇到这种情况,提示我们正在使用过时的方法

public class Men {
    @Deprecated
    public void say(){
        
    }
    
    public void speak(){
        
    }
}

在这里插入图片描述
@Override
用于标明此方法覆盖了父类的方法

@SuppressWarnings
用于有选择的关闭,编译器对类,变量的警告

其源码

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

其内部有个String 数组接受如下的值

deprecation:使用了不赞成使用的类或方法时的警告;
unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 
fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
path:在类路径、源文件路径等中有不存在的路径时的警告; 
serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告; 
finally:任何 finally 子句不能正常完成时的警告; 
all:关于以上所有情况的警告。

注解的提取

到现在你已经会了自定义注解,也可以在类中使用自定义的注解,不过现在的注解,跟注释没有太大区别,没有太大的作用,怎么才能让注解工作起来呢?这就离不开反射

注解和反射
我们反编译注解类,发现他其实是继承自Annotation接口,也就是说java 用Annotation接口代表注解,Annotation是所有注解的父类

public interface DBTable extends Annotation{
    public abstract String name();
}

为了运行时获取注解的信息,java 在反射包中增加了AnnotatedElement接口,它主要用于表示正在JVM运行的程序中已使用的注解元素,通过该接口提供的方法,可以利用反射技术提取注解的信息,如反射包的Constructor类、Field类、Method类、Package类和Class类都实现了AnnotatedElement接口,它简要含义如下

Class:类的Class对象定义   
Constructor:代表类的构造器定义   
Field:代表类的成员变量定义 
Method:代表类的方法定义   
Package:代表类的包定义
返回值方法名称说明
< A extends Annotation>getAnnotation(Class< A> annotationClass)该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。
Annotation[]getAnnotations()返回此元素上存在的所有注解,包括从父类继承的
booleanisAnnotationPresent(Class<? extends Annotation> annotationClass)如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
Annotation[]getDeclaredAnnotations()返回直接存在于此元素上的所有注解,注意,不包括父类的注解,调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响,没有则返回长度为0的数组

@Text(id = 11, message = "22")
public class C {
    @Check("33")
    public int a;

    @Text1(id = 44, message = "55")
    public void f() {

    }

    public static void main(String[] args) {
        Class<C> cClass = C.class;
        boolean annotationPresent = cClass.isAnnotationPresent(Text.class);
        if (annotationPresent) {
            Text annotation = cClass.getAnnotation(Text.class);
            System.out.println("获取类的注解" + annotation.message() + "/" + annotation.id());
        }


        try {
            Field a = cClass.getField("a");
            //获取a上的注解
            Check check = a.getAnnotation(Check.class);
            if (check != null) {
                System.out.println("获取字段上的注解" + check.value());
            }

            Method f = cClass.getMethod("f");
            Text1 text1 = f.getAnnotation(Text1.class);
            if (text1 != null) {
                System.out.println("获取方法上的注解" + text1.message() + "/" + text1.id());
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

获取类的注解22/11
获取字段上的注解33
获取方法上的注解55/44

注解的使用场景

那么注解到底有什么用呢?
看下官方的解释

注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。

注解有许多用处,主要用处如下,

1 提供信息给编译器:编译器可以利用注解来探测错误和警告信息
2 编译阶段时的处理:软件工具可以用注解信息生成代码,HTML文档,或者其他相应的处理
3 运行时的处理:某些注解可以运行时接受代码提取

当开发者用注解修饰了类,变量,方法,这些注解不会自己生效,必须?开发者提供相应的代码处理注解,这些提取和处理注解的代码统称为,注解处理器

注解应用实例
ButterKnife,Dagger2,Retrofit,EventBus,使用了注解

参考:https://blog.csdn.net/briblue/article/details/73824058
https://blog.csdn.net/javazejian/article/details/71860633
Java编程思想

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值