概述
在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;
}
}