From e45def4c8268354c7710bff8d7b530a9d1bb17e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E7=A5=A5?= <1366971433@qq.com> Date: Mon, 16 Dec 2019 21:25:59 +0800 Subject: [PATCH] =?UTF-8?q?Java=E5=8F=8D=E5=B0=84=E4=B8=8E=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/Java_反射与注解.md | 85 ++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/notes/Java_反射与注解.md b/notes/Java_反射与注解.md index 81d0ed3..56164fe 100644 --- a/notes/Java_反射与注解.md +++ b/notes/Java_反射与注解.md @@ -1,26 +1,40 @@ -# Java 反射 +# Java 反射与注解 + + ## 一、Class 类 ### 1.1 Class 对象 -在 Java 中,每个已加载的类在内存中都有一份类信息,类信息对应的类是 java.lang.Class,每个对象都持有指向它所属类信息的引用。所以想要获取 Class 对象,有以下三种方法: +在 Java 中,每个已加载的类在内存中都有一份类信息,类信息对应的类是 `java.lang.Class`,每个对象都持有指向它所属类信息的引用。所以想要获取 Class 对象,有以下三种方法: -+ 通过类名获取: +1. 通过类名获取: ```java Class dateClass = Date.class; Class integerClass = int.class; ``` -+ 通过对象的`getClass()`方法获取: +2. 通过对象的`getClass()`方法获取: ```java Date date = new Date(); Class aClass = date.getClass(); ``` -+ 通过 Class 类的静态方法 `forName` 获取: +3. 通过 Class 类的静态方法 `forName` 获取: ```java Class aClass = Class.forName("java.util.Date"); @@ -43,7 +57,7 @@ Class 提供了如下三个方法,由于获取名称信息,其作用和输 | String[].class | [Ljava.lang.String; | String[] | java.lang.String[] | | ArrayList.class | java.util.ArrayList | ArrayList | java.util.ArrayList | -对于数组类型的getName返回值,使用前缀`[`表示数组,有几个`[`表示是几维数组,数组类型使用字符表示:boolean(Z)、byte(B)、char(C)、double(D)、float(F)、int(I)、long(J)、short(S)、接口和类(L)。 +对于数组类型的getName返回值,使用前缀`[`表示数组,有几个`[`表示是几维数组,数组类型使用字符表示:`boolean(Z)`、`byte(B)`、`char(C)`、`double(D)`、`float(F)`、`int(I)`、`long(J)`、`short(S)`、`接口和类(L)`。 ### 1.3 构造器 @@ -60,7 +74,7 @@ public Constructor getConstructor(Class... parameterTypes) public Constructor getDeclaredConstructor(Class... parameterTypes) ``` -获取指定的构造器后,可以使用`newInstance`方法来创建其实例,实例如下: +获取指定的构造器后,可以使用 `newInstance` 方法来创建其实例,实例如下: ```java class Test { @@ -87,7 +101,7 @@ class Test { } } -输出:Student{name='heibaiying', age=10} +// 输出:Student{name='heibaiying', age=10} ``` 如果你只是想调用默认的无参构造器,则可以直接使用 Class 对象的`newInstance`方法: @@ -146,7 +160,7 @@ class Test { System.out.println(field.get(student)); } } -输出: heibaiying +// 输出: heibaiying ``` ### 1.5 方法信息 @@ -195,12 +209,12 @@ class Test { System.out.println(geMethod.invoke(student)); } } -输出: heibaiying +// 输出: heibaiying ``` ### 1.6 类型检查 -想要判断某个对象是否是某个类或其子类的示例,可以使用`instanceof`关键字,或者使用 Class 的 `isInstance`方法,示例如下: +想要判断某个对象是否是某个类或其子类的示例,可以使用 `instanceof` 关键字,或者使用 Class 的 `isInstance` 方法,示例如下: ```java static class Manager {} @@ -225,7 +239,7 @@ employee.getClass().equals(Manager.class); // false employee.getClass().equals(Employee.class); // true ``` -在知道对象的类型后,如果你需要对其进行类型转换,则可以使用类型转换语法或者 Class 的`cast`方法: +在知道对象的类型后,如果你需要对其进行类型转换,则可以使用类型转换语法或者 Class 的 `cast` 方法: ```java Manager manager01 = Manager.class.cast(employee); @@ -238,7 +252,7 @@ Manager manager02 = (Manager) employee; ### 2.1 注解定义 -下面是`@Override`注解的定义,所有注解均使用`@interface`关键字修饰,`@Target`定义注解的运用对象,`@Retention`表示注解信息保留到什么时候。 +下面是 `@Override` 注解的定义,所有注解均使用 `@interface` 关键字修饰, `@Target` 定义注解的运用对象,`@Retention` 表示注解信息保留到什么时候: ```java @Target(ElementType.METHOD) @@ -247,32 +261,30 @@ public @interface Override { } ``` -`@Target`有以下可选值,其含义分别如下: +`@Target` 有以下可选值,其含义分别如下: -- **TYPE**:表示类、接口(包括注释类型)或枚举声明 -- **FIELD**:字段声明(包括枚举常量) -- **METHOD**:方法声明 -- **PARAMETER**:参数声明 -- **CONSTRUCTOR**:构造器声明 -- **LOCAL_VARIABLE**:本地变量声明 -- **ANNOTATION_TYPE**:注解声明 -- **PACKAGE**:包声明 -- **TYPE_PARAMETER**:类型参数声明 -- **TYPE_USE**:任何使用类型的语句 +- **TYPE**:表示类、接口(包括注释类型)或枚举声明; +- **FIELD**:字段声明(包括枚举常量); +- **METHOD**:方法声明; +- **PARAMETER**:参数声明; +- **CONSTRUCTOR**:构造器声明; +- **LOCAL_VARIABLE**:本地变量声明; +- **ANNOTATION_TYPE**:注解声明; +- **PACKAGE**:包声明; +- **TYPE_PARAMETER**:类型参数声明; +- **TYPE_USE**:任何使用类型的语句。 -`@Retention`有以下可选值,其含义分别如下: - -- **SOURCE**:只在源代码中保留,编译器将代码编译为字节码后就会丢掉。 - -- **CLASS**:保留在字节码文件中,但虚拟机将 class 文件加载到内存时不一定会在内存中保留,这是默认的行为。 +`@Retention` 有以下可选值,其含义分别如下: +- **SOURCE**:只在源代码中保留,编译器将代码编译为字节码后就会丢掉; +- **CLASS**:保留在字节码文件中,但虚拟机将 class 文件加载到内存时不一定会在内存中保留,这是默认的行为; - **RUNTIME**:一直保留到运行时,可以通过反射获取其信息。 ### 2.2 注解信息 -对于`@Retention`类型为`RUNTIME`的注解,可以利用反射机制查看其信息。因为注解可以运用在不同目标上,所以 Class 、Field、Method、Constructor 都有如下方法: +对于 `@Retention` 类型为 `RUNTIME` 的注解,可以利用反射机制查看其信息。因为注解可以运用在不同目标上,所以 Class 、Field、Method、Constructor 都有如下方法: -``` +```java // 获取所有注解 public Annotation[] getAnnotations() public Annotation[] getDeclaredAnnotations() @@ -291,13 +303,11 @@ public @interface Json { } ``` - - ```java class Test { static class Student { - /*当只有一个值并且其对应的方法名为value时候,可以省略 value = */ + /*当只有一个值并且其对应的方法名为value时候,可以省略value = */ @Json("姓名") private String name; @Json(value = "出生日期", format = "yyyy-MM-dd HH:mm:ss") @@ -337,7 +347,7 @@ class Test { ### 2.3 注解继承 -一个常用的元注解是`@Inherited`,它表示某个注解是否能够被继承。示例如下: +一个常用的元注解是 `@Inherited`,它表示某个注解是否能够被继承。示例如下: ```java @Target(ElementType.TYPE) @@ -348,7 +358,7 @@ public @interface ClassName { } ``` -使用示例如下:此时如果加上`@Inherited`注解,则两者的输出都是 true;如果不加上`@Inherited`,第二行语句输出 false,代表子类 PrimaryStudent 没有继承到` @ClassName`注解。 +使用示例如下,此时如果加上 `@Inherited` 注解,则两者的输出都是 true;如果不加上 `@Inherited` ,第二行语句输出 false,代表子类 PrimaryStudent 没有继承到 `@ClassName` 注解: ```java class Test { @@ -367,3 +377,6 @@ class Test { +## 参考资料 + ++ 马俊昌 . Java编程的逻辑 . 机械工业出版社 . 2018-01-01 \ No newline at end of file