概述
在JDK5之后提供了一个新特性,和类、接口同级。定义时使用的关键字是@interface
。注解主要有三个作用,分别是编译检查、替代配置文件、定义注解(元注解)、分析代码(用到反射)。注解的本质就是接口
,可通过反编译注解的字节码文件。
Java中的3个常用注解
@Override
@Override
注解主要是用于编译检查,子类重写父类的方法,重写的方法上面有该注解,一旦我们修改重写方法名就会报错。当我们删除@Override
,再修改就不会报错了,这样编译器会认为这个方法是开发者自定义的方法
@Override
public String toString() {
return super.toString();
}
@SuppressWarnings
@SuppressWarnings
注解作用是用于消除警告。比如我们定义一个变量,当变量未使用时,编译器会提示警告信息。对于这些警告如果你不想被提示,可以在方法名添加该注解。注解属性有很多取值,一般我们赋值"all",就意味着消除所有⚠️。
@SuppressWarnings("all")
public static void main(String[] args) {
int a = 10;
}
@Deprecated
@Deprecated
注解适用于提示方法不建议使用,可能改方法有bug或者有新的方法替代了。如果我们调用该注解表明的方法会有中划线
提示。
如果我们写一个框架对外提供的接口想要告诉调用者该方法已经过期。也可以使用该注解声明。
@Deprecated
public static void test(){
}
自定义注解
注解的定义与基本使用
自定义一个注解跟类、接口格式一样,只是修饰的关键字是@interface
。概述中说过注解的本质就是接口,那么跟接口一样,接口中可以有常量和抽象方法。抽象方法在注解中就称之为注解属性
。
public @interface MyAnnotation {
// 定义一个注解属性age
public int age();
public String[] names();
}
在MyAnnotation注解定义了一个test属性,该注解属性类型为int。 注意:注解属性类型只支持基本数据类型、Class、String、Annotation、Enum枚举
。
定义了MyAnnotation注解后,我们就可以在其它类中使用注解。
package com.coderhong.annotation;
// 给注解属性test赋值10
@MyAnnotation(age =10, names="{jake, rose}")
public class MyAnnotationExample {
}
一旦注解中声明了属性,使用注解是必须对所有属性赋值,否者报错。
当注解只有一个属性,且该属性名为value,在给注解属性赋值是可以省略属性名。
public @interface MyAnnotation {
public String value();
}
// 省略属性名
@MyAnnotation("rose")
public class MyAnnotationExample {
}
元注解
上面的自定义注解我们将注解作用在类上,其实它还可以作用在接口、方法、字段等上面。那么这个通过什么机制去控制呢,这就需要了解元注解
。元注解就是作用在注解上的注解。我们常见的元注解@Retention
与@Target
。
@Retention
定义注解保留到什么阶段
@Retention取值 | 注解保留到什么阶段 |
---|---|
RetentionPolicy.SOURCE | 只在代码中保留,在字节码文件中就删除了 |
RetentionPolicy.CLASS | 只在代码和字节码文件中都保留 |
RetentionPolicy.CLASS | 只在代码和字节码文件中都保留 |
RetentionPolicy.RUNTIME | 所有阶段都保留 |
@Retention使用示例:
//@Retention(RetentionPolicy.RUNTIME)
//@Retention(RetentionPolicy.SOURCE)
//@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
public String value();
}
@Target
@Target规定注解作用在什么上面。
@Target取值 | 作用目标 |
---|---|
ElementType.TYPE | 作用在类、接口等上面 |
ElementType.METHOD | 作用在方法上面 |
ElementType.FIELD | 作用在字段上面 |
//@Target(ElementType.TYPE)
//@Target(ElementType.METHOD)
@Target(ElementType.FIELD)
public @interface MyAnnotation {
public String value();
}
注解的使用示例
通过注解模拟JUint实现
自定义一个注解MyAnnotation跟两个Java类Test、MainClass。 通过执行MainClass类中的main方法调用Test类中所有被MyAnnotation修饰的方法。
这里主要运用到的技术就是注解+反射。通过反射获取Test类中所有方法,遍历方法数组拿到每一个Method对象,通过isAnnotationPresent();判断方法是否被某个注解修饰。
Boolean flag = method.isAnnotationPresent(MyAnnotation.class);
然后调用。
这里主要看下MainClass类中的实现
// 执行main 执行TestClass中有MyAnnotation注解声明的方法
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
// 获取TestClass的字节码文件
Class clazz = TestClass.class;
// 获取所有方法
Method[] methods = clazz.getMethods();
// 遍历所有方法
for (Method method : methods) {
// 判断方法时候有指定注解
Boolean flag = method.isAnnotationPresent(MyAnnotation.class);
// 判断是否包含MyAnnotation注解 如果包含就执行方法
if(flag){
method.invoke(clazz.newInstance());
}
}
}
注解替代JDBC的配置文件
定义一个注解JDBCAnnotation
,声明属性对应了JDBC获取连接所需的参数信息。在工具类JDBCUtils
的getConnection方法声明注解并对注解属性进行赋值。在调用getConnection方法获取连接时,通过映射技术获取getConnection的Method,载通过Method的getAnnotation获取该方法的注解,从而获取注解属性值。
JDBCAnnotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JDBCAnnotation {
// default 给注解属性设置默认值
public String DriverClass() default "com.mysql.jdbc.Driver";
public String url() default "jdbc:mysql://localhost:3306/myDB";
public String user() default "root";
public String password();
}
JDBCUtils
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCUtils {
@JDBCAnnotation(password="123456", user="root")
public static Connection getConnection() throws NoSuchMethodException, SecurityException, ClassNotFoundException, SQLException{
Class clazz = JDBCUtils.class;
// 获取getConnection对应的Method
Method method = clazz.getMethod("getConnection");
// 判断是否包含@JDBCAnnotation注解
if(method.isAnnotationPresent(JDBCAnnotation.class)){
// 通过Method获取注解
JDBCAnnotation annotation = method.getAnnotation(JDBCAnnotation.class);
// 通过注解获取属性value
String driverClass = annotation.DriverClass();
String url = annotation.url();
String user = annotation.user();
String password = annotation.password();
// 注册驱动
Class.forName(driverClass);
// 获取连接
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
return null;
}
}