註解不是程式本身,可以在程式編譯、類載入和執行時被讀取,並執行相應的處理。註解的格式為"@註釋名(引數值)",可以附加在包、類、方法和欄位上,通過反射機制實現實現註解的存取。
該註解表示覆蓋的是其父類別的方法,當子類重寫父類別方法時,確保子類確實重寫了父類別的方法,避免出現低階錯誤
/**
* 該註解標識覆蓋的是其父類別的方法,當子類重寫父類別方法時,確保子類確實重寫了父類別的方法,避免出現低階錯誤
* @return
*/
@Override
public String toString() {
return super.toString();
}
該註解表示某個屬性、方法或類等已過時(程式設計師不鼓勵使用的程式元素,通常是因為它是危險的,或者因為存在更好的替代方法),當其他程式使用已過時的屬性、方法或者類時,編譯器會給出警告(刪除線)。
/**
* 該註解表示此方法已過時,存在危險,不推薦使用,其有代替方法,如果繼續使用會通過刪除線進行標識
*/
@Deprecated
public static void test() {
System.out.println("標記已過時");
}
該註解作用的類、方法和屬性會取消顯示編譯器警告,其引數主要是進行警告說明以及取消(unchecked)等。
@SuppressWarnings("取消此類的所有警告")
public class BuiltAnnotation {
@SuppressWarnings("取消此屬性的警告")
private String username;
@SuppressWarnings("取消此方法的警告")
public static void main(String[] args) {
// ...
}
}
元註解的作用就是負責註解其他註解,Java定義了4個標準的元註解型別,他們被用來提供對其他註解的作用範圍及型別進行說明,通過元註解可以自定義其他註解。
例如@Target(ElementType.METHOD)表示作用在方法上,@Target(ElementType.TYPE)表示作用在類或介面上等
/**
* @Target註解:描述註解的使用範圍
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* 類或介面:ElementType.TYPE;
* 欄位:ElementType.FIELD;
* 方法:ElementType.METHOD;
* 構造方法:ElementType.CONSTRUCTOR;
* 方法引數:ElementType.PARAMETER;
* ...
*/
ElementType[] value();
}
通常自定義的註解都使用@Retention(RetentionPolicy.RUNTIME),也就是執行時期作用。
/**
* @Retention:表示需要在什麼級別儲存該註解資訊,用於描述註解的生命週期
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* RetentionPolicy.SOURCE:僅編譯期,註解將被編譯器丟棄。
* RetentionPolicy.CLASS:僅class檔案,註釋將由編譯器記錄在類檔案中,但VM不需要在執行時保留,如果不指定則預設為class。
* RetentionPolicy.RUNTIME:執行期,註釋將由編譯器記錄在類檔案中,並由VM在執行時保留,因此可以反射讀取。通常自定義的註解都是RUNTIME。
* 範圍:RUNTIME>CLASS>SOURCE
*/
RetentionPolicy value();
}
@Inherited僅針對 @Target(ElementType.TYPE) 型別的註解有用,並且只能是 class 的繼承,對 interface 的繼承無效:
/**
* 1. 使用@interface定義註解;
* 3. 通過元註解設定該註解,設定註解的使用範圍和生命週期等
* @author Loner
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Report{
/**
* 2. 新增引數、預設值,如果沒有預設值,就必須給引數賦值,一般把最常用的引數定義為value(),推薦所有引數都儘量設定預設值
* 形式為:引數型別 引數名();
*/
int type() default 0;
String value() default "LonerMJ";
}
@Report(type = 1, value = "test")
public class CustomerAnnotation {
@Report(type = 1, value = "test")
public void testCustomerAnnotation() {
System.out.println("測試自定義註解");
}
}
Reflection(反射)是指程式在執行期可以拿到一個物件的所有資訊。
反射機制是指程式在執行時,通過Reflection API獲取任何類的內容資訊,並能直接操作任何物件的內部屬性及方法。
java.lang.Class類,實現反射的核心類,類載入完成之後,在堆記憶體的方法區中就會產生一個Class物件(一個類只有一個Class物件),這個物件包含了類的完整結構資訊,通過這個物件看到類的結構。
public class InstantiationClass {
public static void main(String[] args) throws ClassNotFoundException {
Teacher teacher = new Teacher("張三", "123456");
// 方式一:呼叫Class類的靜態方法forName(String className)
Class<?> c1 = Class.forName("com.loner.mj.reflection.Teacher");
// 方式二:已知某個類的範例,呼叫該範例的getClass()方法,getClass是Object類中的方法。
Class<? extends Teacher> c2 = teacher.getClass();
// 方式三:已知具體類,通過類的class屬性獲取,該方法最安全可靠,程式效能最高
Class<Teacher> c3 = Teacher.class;
// 方式四:通過基本內建型別的包裝類的TYPE屬性獲得CLass範例
Class<Integer> c4 = Integer.TYPE;
// 方式五:通過當前子類的Class物件獲得父類別的Class物件
Class<?> c5 = c1.getSuperclass();
}
}
方法名 | 方法功能 |
---|---|
static Class forName(String name) | 返回指定類名的Class物件 |
Obiect newInstance() | 呼叫無參建構函式,返回Class物件的一個範例 |
String getName() | 返回此Class物件所表示的實體(類,介面,陣列類或void)的名稱 |
Class getSuperclass() | 返回當前Class物件的父類別的Class物件 |
Class[] getinterfaces() | 返回當前Class物件的介面 |
ClassLoader getClassLoader() | 返回該類的類載入器 |
Method getDeclareMethod(String name, Class<?> ... parameterTypes) | 獲取方法名和參數列匹配的方法 |
Method[] getDeclareMethods() | 獲取所有非繼承的方法 |
Method[] getMethods() | 獲取所有非私有方法 |
Field getDeclareField(String name) | 獲取指定屬性 |
Field[] getDeclareFields() | 獲取所有屬性 |
Field[] getFields() | 獲取所有非私有屬性 |
Constructor |
獲取參數列匹配的構造方法 |
Constructor |
獲取類的所有構造方法 |
A getAnnotation(Class<?> annotationClass) | 返回指定註解 |
Annotation[] getDeclaredAnnotations() | 返回所有註解 |
public class ReflectionMethods {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
Class<Worker> workerClass = Worker.class;
/**
* 類
*/
System.out.println(workerClass.getName());
System.out.println(workerClass.getSimpleName());
System.out.println(workerClass.getSuperclass());
System.out.println(workerClass.getPackage());
Class<?>[] interfaces = workerClass.getInterfaces();
for (Class<?> i : interfaces) {
System.out.println(i);
}
/**
* 屬性
*/
// 獲取所有的屬性
Field[] declaredFields = workerClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// 獲取指定屬性
System.out.println(workerClass.getDeclaredField("username"));
// 獲取所有公共屬性
Field[] fields = workerClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
/**
* 構造方法
*/
// 獲取所有構造方法
Constructor<?>[] declaredConstructors = workerClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
// 獲取指定的構造方法
System.out.println(workerClass.getDeclaredConstructor(String.class, String.class));
/**
* 方法
*/
// 獲取所有的方法
Method[] declaredMethods = workerClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
// 獲取指定方法
System.out.println(workerClass.getDeclaredMethod("getUsername", null));
// 獲取所有功能方法
Method[] methods = workerClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
public class InstantiationClass {
public static void main(String[] args) throws ClassNotFoundException {
// 類(外部類,成員(成員內部類,靜態內部類),區域性內部類,匿名內部類。)
Class<Object> objectClass = Object.class;
// 介面
Class<Comparable> comparableClass = Comparable.class;
// 陣列
Class<String[]> stringClass = String[].class;
Class<int[][]> intClass = int[][].class;
// 列舉
Class<ElementType> elementTypeClass = ElementType.class;
// 註解
Class<Override> overrideClass = Override.class;
// 基本資料型別
Class<Integer> integerClass = Integer.class;
// void
Class<Void> voidClass = void.class;
// Class
Class<Class> classClass = Class.class;
}
}
public class UseClass {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class<User> userClass = User.class;
/**
* 通過構造器範例化物件:不使用構造器,預設通過無參構造進行物件建立
*/
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
User user = declaredConstructor.newInstance("張三", "123456");
System.out.println(user);
/**
* 呼叫方法並執行相關操作
*/
Method setUsername = userClass.getDeclaredMethod("setUsername", String.class);
// invoke(Object, 引數):啟用,即執行相關操作為該物件
setUsername.invoke(user, "李四");
Method setPassword = userClass.getDeclaredMethod("setPassword", String.class);
setPassword.invoke(user, "123456");
System.out.println(user);
/**
* 操作屬性:通過反射直接操作私有屬性會報錯,需要通過setAccessible(ture)關閉存取安全檢查,此方法屬性、方法和構造都具有,會影響效率
*/
Field username = userClass.getDeclaredField("username");
username.setAccessible(true);
username.set(user, "使用者名稱");
System.out.println(user);
}
}
Java採用泛型擦除的機制來引入泛型,Java中的泛型僅僅是給編譯器javac使用的,確保資料的安全性和免去強制型別轉換問題。但是,一旦編譯完成,所有和泛型有關的型別全部擦除。
為了通過反射操作這些型別,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種型別來代表不能被歸一到Class類中的型別但是又和原始型別齊名的型別。
ParameterizedType:表示一種引數化型別,比如Collection
GenericArrayType:表示一種元素型別是引數化型別或者型別變數的陣列型別
TypeVariable:是各種型別變數的公共父介面
WildcardType:代表一種萬用字元型別表示式
public class ClassOperateGenerics {
public Map<String, String> list() {
System.out.println("返回值是泛型");
return new HashMap<>();
}
public void test(Map<String, User> map, List<Integer> list) {
System.out.println("引數是泛型");
}
public static void main(String[] args) throws NoSuchMethodException {
/**
* 獲取方法引數的泛型
*/
Method method = ClassOperateGenerics.class.getMethod("test", Map.class, List.class);
// 獲取所有方法引數的泛型
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
// java.util.Map<java.lang.String, com.loner.mj.reflection.User>
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
// 獲取所有泛型的真實引數
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
// String, User, Integer
System.out.println(actualTypeArgument);
}
}
}
/**
* 獲取方法返回值的泛型
*/
Method list = ClassOperateGenerics.class.getMethod("list", null);
// 獲取方法返回值的泛型
Type genericReturnType = list.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
// 獲取所有泛型的真實引數
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
public class ClassOperateAnnotation {
public static void main(String[] args) throws NoSuchFieldException {
Class<People> peopleClass = People.class;
// 獲取類的所有註解
Annotation[] declaredAnnotations = peopleClass.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
}
// 獲取類的註解的值
Table declaredAnnotation = peopleClass.getDeclaredAnnotation(Table.class);
System.out.println(declaredAnnotation.value());
// 獲取屬性的註解
Field name = peopleClass.getDeclaredField("name");
Fields annotation = name.getAnnotation(Fields.class);
System.out.println(annotation.name());
}
}