Java注解
从JDK5开始,Java增加对元数据的支持,也就是注解,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
1. 基本内置注解
@Override
用在方法上,表示这个方法重写了父类的方法。如果父类没有这个方法,那么就无法编译通过。
@Deprecated
表示这个方法已经过期,不建议开发者使用。
@SuppressWarnings
英文的意思是抑制的意思,这个注解的用处是忽略警告信息。
有常见的值分别对应如下意思:
- deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告);
- unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
- fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
- path:在类路径、源文件路径等中有不存在的路径时的警告;
- serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
- finally:任何 finally 子句不能正常完成时的警告;
- rawtypes 泛型类型未指明
- unused 引用定义了,但是没有被使用
- all:关于以上所有情况的警告。
@SafeVarargs
暂时忽略
@FunctionalInterface
Java1.8 新增的注解,用于约定函数式接口。
函数式接口概念: 如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口称为函数式接口。函数式接口其存在的意义,主要是配合Lambda 表达式 来使用。
2. 自定义注解@JDBCConfig
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//元注解
@Target({METHOD,TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JDBCConfig {
//注解元素
String ip();
int port() default 3306;
String database();
String encoding();
String loginName();
String password();
}
1. 创建注解类型
public @interface JDBCConfig
2. 元注解
@Target({METHOD,TYPE}) 表示这个注解可以用用在类/接口上,还可以用在方法上
@Retention(RetentionPolicy.RUNTIME) 表示这是一个运行时注解,即运行起来之后,才获取注解中的相关信息,而不像基本注解如@Override那种不用运行,在编译时就可以进行相关工作的编译时注解。
@Inherited 表示这个注解可以被子类继承
@Documented 表示当执行javadoc的时候,本注解会生成相关文档
3. 注解元素
注解元素用于存放注解信息,在解析的时候获取出来。
在此例中,若注解的方法是value的时候,给注解赋值时可以省略@JDBCConfig(xxx=“123”),
改为@JDBCConfig(“123”)
4. 使用自定义注解方式完成DBUtils
@JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "123456")
public class DBUtil {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException, NoSuchMethodException, SecurityException {
//通过反射获取DBUtils类上的注解对象
JDBCConfig config = DBUtil.class.getAnnotation(JDBCConfig.class);
String ip = config.ip();
int port = config.port();
String database = config.database();
String encoding = config.encoding();
String loginName = config.loginName();
String password = config.password();
String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding);
return DriverManager.getConnection(url, loginName, password);
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, SQLException {
Connection c = getConnection();
System.out.println(c);
}
}
3. 元注解
-
@Target:表示这个注解能放在什么位置上。
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包 -
Retention
表示生命周期,可选值有3个
RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就没了。@Override 就是这种注解。
RetentionPolicy.CLASS: 注解在java文件编程成.class文件后,依然存在,但是运行起来后就没了。@Retention的默认值,即当没有显式指定@Retention的时候,就会是这种类型。
RetentionPolicy.RUNTIME: 注解在运行起来之后依然存在,程序可以通过反射获取这些信息,自定义注解@JDBCConfig 就是这样。 -
@Inherited
表示该注解具有继承性。使用该注解的类的子类可以获取到父类的注解信息。
-
@Documented
在用javadoc命令生成API文档后,DBUtil的文档里会出现该注解说明。
-
@Repeatable
当没有@Repeatable修饰的时候,注解在同一个位置只能出现一次,否则会报错,使用@Repeatable之后,再配合一些其他动作,就可以在同一个地方使用多次了。用法如下:
public class FindFiles { @Target( METHOD) @Retention( RetentionPolicy.RUNTIME ) public @interface FileTypes { FileType[] value(); } @Target( METHOD ) @Retention( RetentionPolicy.RUNTIME ) @Repeatable( FileTypes.class ) public @interface FileType { String value(); }; /**因为使用了@Repeatable,所以可以在此多次使用*/ @FileType( ".java" ) @FileType( ".html" ) @FileType( ".css" ) @FileType( ".js" ) public void work(){ try { FileType[] fileTypes= this.getClass().getMethod("work").getAnnotationsByType(FileType.class); System.out.println("将从如下后缀名的文件中查找文件内容"); for (FileType fileType : fileTypes) { System.out.println(fileType.value()); } System.out.println("查找过程略。。。"); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { new FindFiles().work(); } }