Java注解介绍


JAVA注解

一、注解和注释区别:

1.1 注释:comment

给程序员看的,对程序做出解释。用于描述代码的作用和一些关键性的知识点,使用文字描述程序。

1.2 注解:annotation

  • JDK5.0后引入的新技术,他不是程序本身,但可以对程序做出解释。(这一点和注释没有区别)

  • 给程序员看,但主要目的是给程序看(多的这个“解”字)

二、注解详细定义

叫元数据,一种代码级别的说明,它是JDK1.5及以后版本引入的一个特性,与类、接口(注解本质上是一种特殊的接口)、枚举在同一个层次,它可以声明在包、类、字段、局部变量、方法参数等的前面,用来对这些元素进行说明、注释。很多框架的底层都是通过注解实现,比如spring boot,spring cloud。(框架的底层就是注解和反射)

2.1 注解的作用分类

编写文档:

通过代码里表示的元数据生成文档【生成doc文档】

代码分析:

通过代码里表示的元数据进行分析【使用反射】

编译检查:

通过代码里表示的元数据让编译器能够实现基本的编译检查【Override】

2.2 注解按照运行机制分类

源码注解:

注解只在源码中存在,编译成.class文件之后就不存在了。常见的注解为@Override,@SuppressWarnings

编译时注解:

注解在源码存在的基础上,也会在.class文件中存在,但是在运行阶段中就不存在了

这是默认的注解保留策略。这种策略下,注解将存在与.class文件,但是不能被运行时访问。通常这种注解策略用来处于一些字节码级别的操作。

运行时注解:

注解在运行阶段依然存在,且能够影响程序的运行过程,例如:@Autowired

通常情况下,我们都会结合反射来做一些事情。

2.3 注解的作用

  • 不是程序本身,可以对程序做出解释(这一点和注释一样)

  • 可以被其他程序(比如:编译器)读取,注解+反射。

  • 可以附加在package,class,method,field等上面,相当于给他们额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。

2.4 注解的格式

注解是以“@注解名”在代码中存在的;还可以添加一些参数值,例如:@suppressWarning(value=“unchecked”)

三、注解入门

分为内置注解和自定义注解

3.1 内置注解示例:

@Override:重写Object的toString()

@Override表示重写父类方法,在编译时存在

package com.happy;

//什么是注解
public class AnnotationStudy extends Object {

    //@Override 重写的注解
    @Override
    public String toString() {
        return super.toString();

    }


    public void testTread(){
        Thread thread=new Thread();

    }
}

@FunctionalInterface:Runnable接口用

线程接口Runnable的@FunctionalInterface,表示该接口是一个函数式编程接口(即只有一个待实现方法),不定义也没有影响程序执行。

package java.lang;

/**
 * The Runnable interface should be implemented by any
 * class whose instances are intended to be executed by a thread. The
 * class must define a method of no arguments called run.
 * 

* This interface is designed to provide a common protocol for objects that * wish to execute code while they are active. For example, * Runnable is implemented by class Thread. * Being active simply means that a thread has been started and has not * yet been stopped. *

* In addition, Runnable provides the means for a class to be * active while not subclassing Thread. A class that implements * Runnable can run without subclassing Thread * by instantiating a Thread instance and passing itself in * as the target. In most cases, the Runnable interface should * be used if you are only planning to override the run() * method and no other Thread methods. * This is important because classes should not be subclassed * unless the programmer intends on modifying or enhancing the fundamental * behavior of the class. * * @author Arthur van Hoff * @see java.lang.Thread * @see java.util.concurrent.Callable * @since JDK1.0 */ @FunctionalInterface public interface Runnable { /** * When an object implementing interface Runnable is used * to create a thread, starting the thread causes the object's * run method to be called in that separately executing * thread. *

* The general contract of the method run is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }

destroy():Thread类的方法用@Deprecated

表示该方法废弃,在调用该方法时,IDE会以删除线标志该方法,不推荐程序员使用,但可以使用。

如下

@Deprecated
public void destroy() {
    throw new NoSuchMethodError();
}
package com.happy;

//什么是注解
public class AnnotationStudy extends Object {

    //@Override 重写的注解
    @Override
    public String toString() {
        return super.toString();

    }


    public void testTread(){
        Thread thread=new Thread();
        thread.destroy();
    }
}

@suppressWarnings

镇压警告,用来抑制编译时的警告信息,与前面的注释不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好的,我们选择性使用就好了。平时不建议镇压,

@SuppressWarnings("all")

@SuppressWarnings("unchecked")

@SuppressWarnings(value={"unchecked","deprecation"})
package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

/**
 * Indicates that the named compiler warnings should be suppressed in the
 * annotated element (and in all program elements contained in the annotated
 * element).  Note that the set of warnings suppressed in a given element is
 * a superset of the warnings suppressed in all containing elements.  For
 * example, if you annotate a class to suppress one warning and annotate a
 * method to suppress another, both warnings will be suppressed in the method.
 *
 * 

As a matter of style, programmers should always use this annotation * on the most deeply nested element where it is effective. If you want to * suppress a warning in a particular method, you should annotate that * method rather than its class. */ @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** * The set of warnings that are to be suppressed by the compiler in the * annotated element. Duplicate names are permitted. The second and * successive occurrences of a name are ignored. The presence of * unrecognized warning names is not an error: Compilers must * ignore any warning names they do not recognize. They are, however, * free to emit a warning if an annotation contains an unrecognized * warning name. * *

The string {@code "unchecked"} is used to suppress * unchecked warnings. Compiler vendors should document the * additional warning names they support in conjunction with this * annotation type. They are encouraged to cooperate to ensure * that the same names work across multiple compilers. * @return the set of warnings to be suppressed */ String[] value(); }

注意:上面value()看似方法,实际为属性,而Sring为属性的类型,这是注解特殊的地方。

另外注意@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE) 这两个注解,为元注解,将在下面讲解。

加入镇压告警前:

加入压制后,idea不再暗黑提示

3.2 元注解

元注解的作用就是负责注解其他注解,就是解释其他注解的注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明。也是内置注解。

这些类型和他们所支持的类在java.lang.annotation包中可以找到,分别是:

@Target:(重点)

用于描述注解的使用范围

(即:被描述的注解可以用在什么地方)

@Retention:(重点)

表示需要在什么级别保存该注释信息,用于描述注解的生命周期:SOURCERUNTIME

一般我们使用定义为RUNTIME,即运行的时候依然存在有用,重点记忆。

例如:

Runtime定义的,将会在Runtime,Class和Source都存在和生效

而Class定义的,会在Class和Source生效

@Document:

说明该注解将包含在javadoc中

@Inherited:

说明子类可以继承父类中的该注解

测试元注解:

自定义注解,使用元注解,示例如下:

下图Target方法指定用在Method,固注解在类上时报错。

用数组引入多个Target范围后,不再报错

四、自定义注解

使用@ interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,注意前面有@,如果没有@就是普通接口

要点如下:

  • @interface用来声明一个注解,格式public @interface 注解名{定义内容}。

    如果是内部类方式申明注解,就省去public

  • 其中每一个方法实际上是声明了一个配置参数(或者理解为属性),方法的名称就是参数的名称。返回值的类型就是参数的类型

    返回值类型只能是基本类型、class、String、enum

  • 可以通过default类声明参数的默认值

  • 如果只有一个参数成员,一般为参数取名为value,使用时还可以起取消掉

  • 注解元素必须要有值,我们定义注解元素时,通常使用空字符串、0作为默认值

package com.happy;

import java.lang.annotation.*;

@MyAnnotation
public class MetaAnnotationUseStudy {


    @MyAnnotation
    public void test() {

    }

    //    注解可以显示赋值,如果没有默认值,我们必须显示赋值
    @MyAnnotation2(name = "happytest",schools = {"哈佛"})
    public void test2() {

    }
}


@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
@interface MyAnnotation {
}


@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Inherited
//作用范围为到运行时
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {

    //        注解的参数,注意这里不是方法
    String name() default "";

    int age() default 0;

    int id() default -1;//如果默认值为-1,代表不存在

    String[] schools() default {"北郵","清華"};

}

后面会介绍反射,注解必须+反射,才能读取注解里的东西,才能发挥最大功效,是框架的基础。