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:(重点)
表示需要在什么级别保存该注释信息,用于描述注解的生命周期:SOURCE
RUNTIME
一般我们使用定义为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 {"北郵","清華"};
}
后面会介绍反射,注解必须+反射,才能读取注解里的东西,才能发挥最大功效,是框架的基础。