作用**
jdk1.5以后出现的
-
编译检查
@Override 注解 -在编译阶段检查方法是否继承自父类
-
编写文档
javadoc 生成文档
-
代码分析 -jdk预定于的注解
- @override 检查方法是否继承父类
<img src="http://ww1.sinaimg.cn/large/006UamUGly1gilobcj5muj30l80ck0th.jpg" alt="image-20200909210239790.png" style="zoom:50%;" />
<img src="http://ww1.sinaimg.cn/large/006UamUGly1gilobrbk30j30lk0bqjs3.jpg" alt="image-20200909210301542.png" style="zoom:50%;" />
- @Deprecate 当前方法已经废弃,但是可以使用
```java
public void add1() {
//老的方法,不建议在使用。不能直接删除,需要给程序员提示
}
public void add2() {
//新增的方法,希望替代老的方法
}
```
加入@Deprecate注解
```java
@Deprecated
public void add1() {
//老的方法,不建议在使用。不能直接删除,需要给程序员提示
}
public void add2() {
//新增的方法,希望替代老的方法
}
```
![image-20200909210628025.png](https://upload-images.jianshu.io/upload_images/9388376-d9b281f6e7c12c4a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以看到当调用被@Deprecated注解标识的方法的时候,idea工具会提示次方法已经废弃不建议使用,方法中有个-- 。但是方法最终还是可以使用的,只不过给程序员一个提示而已。
- @SuppressWarning 压制所有的警告
可以看到这段代码中有很多的警告⚠️,但是程序照样可以运行。如果我不想看到这些警告怎么办呢?
在类中添加@SuppressWarning("all")方法。
自定义注解
格式
//原注解
public @interface 注解名称 {
//属性
}
//用@interface
自定义
public @interface Myan {
}
注解的本质
把上面的自定义注解经过javac编译 然后在javap反编译看一下
base) -bash-3.2$ javac Myan.java
(base) -bash-3.2$ ls
Myan.class Myan.java
(base) -bash-3.2$ javap Myan.class
Compiled from "Myan.java"
public interface Myan extends java.lang.annotation.Annotation {
}
可以看到反编译之后是这段代码
public interface Myan extends java.lang.annotation.Annotation {
}
说明注解的本质是一个继承java.lang.annotation.Annotation的接口 ,既然他是接口那么他就会有属性常量和方法
<span style="color:red" >注意,方法的返回值只能是如下类型</span>
- 基本类型
- string类型
- 枚举类型
- 注解类型
- 以上类型的数组
public @interface Myan {
//属性常量
public String name = null;
//方法
public String getName();
public int getAge();
public ElementType enunType();
public Myan2 getAn();
public String[] names();
public @interface Myan2 {
}
}
属性
为什么注解定义的方法通常都叫做属性?
当我们使用注解的时候,注解中定义的方法必须都要赋值。
public class Test1 {
@Myan(getName = "1")
public String test() {
return "";
}
}
而给方法赋值的写法特别像在对象中初始化属性。所以通过给注解中定义的方法叫做属性。
多种返回值的属性怎么赋值
public class Test1 {
@Myan(getName = "1",getAge = 1,getAn = @Myan.Myan2,enunType = ElementType.METHOD,names = {"a","b"})
public String test() {
return "";
}
}
分别给5种属性赋值。数组属性赋值需要{}。
default关键字
定义注解使用 default关键字
public @interface Myan2 {
String value() default "my";
}
@Myan2
public String test() {
return "";
}
当属性使用 default关键字初始化属性值的时候, 使用注解可以不设置属性的值。如果不设置使用默认值。
不使用【属性=值】的方式
public @interface Myan2 {
String value();
}
@Myan2("1")
public String test() {
return "";
}
如果注解只有一个属性且属性的名字是value,那么可以直接赋值。不需要使用 key=value的方式
元注解
-
@Target 表示当前注解可以生效的位置。值是ElementType枚举。常用的有
- TYPE可以声明在类上
- FIELD可以声明在类的属性中
- METHOD可以声明在方法中
- PARAMETER 参数
- CONSTRUCTOR构造器
声明一个注解,定义注解只能用在方法上
@Target(ElementType.METHOD) public @interface Myan3 { }
如果用在方法上编译报错。
-
@Retention 描述注解被保留的阶段。
public enum RetentionPolicy { //编译阶段 SOURCE, // 字节码阶段 CLASS, //运行阶段 通常用这个 RUNTIME }
比如说 @SuppressWarnings只在编译阶段有效
@Documented 代表可以生成文档
**@Inherited **描述注解是否可以被子类继承
自定义注解使用案例
自定义一个注解,注解中有2个属性。获取类的全路径 与 获取方法名。通过获取注解中的属性生成一个对象。
定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface InvokeAnno {
//获取类名
String getClassName();
//获取方法名
String getMethodName();
}
例子
@InvokeAnno(getClassName = "com.javaDemo.annotation.Test3",getMethodName = "log")
public class Test3 {
public void log() {
System.out.println("执行方法log----");
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
//获取class类
Class<Test3> test3Class = Test3.class;
//通过反射获取类中的注解
InvokeAnno annotation = test3Class.getAnnotation(InvokeAnno.class);
//获取注解属性
String className = annotation.getClassName();
String methodName = annotation.getMethodName();
//通过反射获取类
Class<?> aClass = Class.forName(className);
Object o = aClass.newInstance();
//通过反射获取方法
Method method = aClass.getMethod(methodName);
//调用方法
method.invoke(o);
}
}