註解和反射學習筆記
註解和反射
本文章參考https://www.bilibili.com/video/BV1p4411P7V3
進行學習和記筆記
註解
什麼是註解
Annotation是從JDK5.0開始引|入的新技術.
Annotation的作用:
- 不是程式本身,可以對程式作出解釋.(這一點和註釋(comment)沒什麼區別)
- 可以被其他程式(比如:編譯器等)讀取.
Annotation的格式:
- 註解是以"@註釋名"在程式碼中存在的, 還可以新增一些引數值,例
如:@SuppressWarnings(value=“unchecked”).
◆Annotation在哪裡使用?
- 可以附加在package , class , method , field等上面,相當於給他們新增了額外的輔助資訊,
我們可以通過反射機制程式設計實現對這些後設資料的訪問
//什麼是註解
public class Test {
// @Override 重寫的註解
@Override
public String toString() {
return super.toString();
}
}
內建註解
-
@Override :定義在java.lang.Override中,此註釋只適用於修辭方法,表示一個方法宣告打算
重寫超類中的另一個方法宣告. -
@Deprecated :定義在java.lang.Deprecated中,此註釋可以用於修辭方法,屬性,類,表示不
鼓勵程式設計師使用這樣的元素,通常是因為它很危險或者存在更好的選擇. -
@SuppressWarnings :定義在java.lang.SuppressWarnings中,用來抑制編譯時的警告資訊.
與前兩個註釋有所不同,你需要新增一個引數才能正確使用,這些引數都是已經定義好了的,
我們選擇性的使用就好了.
@SuppressWarningsl"all")
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”,“deprecation”})等等
//什麼是註解
public class Test {
// @Override 重寫的註解
@Override
public String toString() {
return super.toString();
}
// @Deprecated 不推薦程式設計師使用,但是可以使用,或者存在更好的
@Deprecated
public void test(){
}
//鎮壓警告
@SuppressWarnings("all")
public void test02(){
List list = new ArrayList();
}
}
元註解
- 元註解的作用就是負責註解其他註解, Java定義了4個標準的meta-annotation型別,他們被用來
提供對其他annotation型別作說明. - 這些型別和它們所支援的類在java.lang.annotation包中可以找到.( @Target , @Retention,
@Documented , @Inherited )- @Target :用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)
- @Retention :表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期
(SOURCE < CL ASS < RUNTIME) - @Document:說明該註解將被包含在javadoc中
- @Inherited: 說明子類可以繼承父類中的該註解
//定義一個註解
//@Target 表示註解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//@Retention 表示註解在什麼地方還有效
// runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
//@Documented 表示是否將註解生成在javadoc中
@Documented
//@Inherited 子類可以繼承父類的註解
@Inherited
public @interface Myannotation {
}
//測試註解
@Myannotation
public class Test {
@Myannotation
public void test(){
}
}
自定義註解
使用@interface自定義註解時,自動繼承了java.lang .annotatlon.Annotation介面
分析:
@ interface用來宣告一個註解,格式: public @ interface註解名{定義內容}
其中的每一個方法實際上是宣告瞭一個配置引數.
方法的名稱就是引數的名稱.
返回值型別就是引數的型別(返回值只能是基本型別,Class , String , enum ).
可以通過default來宣告引數的預設值
如果只有一個引數成員, 一般引數名為value
註解元素必須要有值,我們定義註解元素時,經常使用空字串,0作為預設值.
//自定義註解
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//註解的引數:型別+引數名 (); 可以加預設值
String name() default "";
int age() default 0;
int id() default 1; //如果預設值為 -1 表示不存在
String[] value() default {"張三","lisi"};
}
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation01 {
String value();
}
@MyAnnotation
public class Test {
//註解可以顯示賦值,如果沒有預設值,我們就必須給註解賦值
@MyAnnotation
public void test(){
}
//註解只有有個引數,且為value 可以省略不寫引數名
@MyAnnotation01("")
public void test2(){
}
}
反射
動態語言
- 是一類在執行時可以改變其結構的語言:例如新的函式、物件、甚至程式碼可以被
引進,已有的函式可以被刪除或是其他結構上的變化。通俗點說就是在執行時代
碼可以根據某些條件改變自身結構。 - 主要動態語言: Object-C. C#、 JavaScript. PHP、 Python等。
靜態語言
- 與動態語言相對應的,執行時結構不可變的語言就是靜態語言。如Java、C、C++。
- Java不是動態語言,但Java可以稱之為“準動態語言”。即Java有一 定的動態性,
我們可以利用反射機制獲得類似動態語言的特性。Java的動態性讓程式設計的時候更
加靈活!
Reflection (反射)
是Java被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API取得任何類的內部資訊,並能直接操作任意物件的內部屬性及方法。
Class C = Class. forName(java.lang.String")
載入完類之後,在堆記憶體的方法區中就產生了一個Class型別的物件(一個類只有一個Class物件),這個物件就包含了完整的類的結構資訊。我們可以通過這個物件看到類的結構。這個物件就像一面鏡子, 透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射
正常方式:引入 需要的"包類”名稱一之通過new例項化取 得例項化物件
演示二
反射方式:例項化物件——>getClass()方法 ——>得到完整的 “包類”名稱
Java反射機制提供的功能
在執行時判斷任意一個物件所屬的類
在執行時構造任意一個類的物件丫
在執行時判斷任意一個類所具有的成員變數和方法
在執行時獲取泛型資訊
在執行時呼叫任意一個物件的成員變數和方法
在執行時處理註解
生成動態代理
…
反射優點和缺點
優點:
可以實現動態建立物件和編譯,體現出很大的靈活性
缺點:
對效能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且
它滿足我們的要求’這類操作總是慢於直接執行相同的操作。
Class類
在Object類中定義了以下的方法,此方法將被所有子類繼承
public final Class getClass()
以上的方法返回值的型別是一個Class 類,此類是Java反射的源頭,實際上所謂反射從程式的執行結果來看也很好理解,即:可以通過物件反射求出類的名稱。
物件照鏡子後可以得到的資訊:某個類的屬性、方法和構造器、某個類到底實現了哪些介面。
對於每個類而言,JRE都為其保留一個不變的Class型別的物件。一個Class物件包含了特
定某個結構(class/interface/enum/annotation/primitive type/void/[])的有關資訊。
- Class本身也是一 個類
- Class 物件只能由系統建立物件
- 一個載入的類在JVM中只會有一個Class例項
- 一個Class物件對應的是一個載入到JVM中的一 個.class檔案
- 每個類的例項都會記得自己是由哪個Class例項所生成
- 通過Class可以完整地得到一個類中的所有被載入的結構
- Class類是Reflection的根源,針對任何你想動態載入、執行的類,唯有先獲得相應的Class物件
Class類的常用方法
方法名 | 功能說明 |
---|---|
static Class.forName(String name) | 返回指定類名name的Class物件 |
Object newlnstance() | 呼叫預設建構函式,返回Class物件的一個例項 |
String getName() | 返回此Class物件所表示的實體(類,介面,陣列類或void)的名稱。 |
Class getSuperClass() | 返回當前Class物件的父類的Class物件 |
Class[] getInterfaces() | 獲取當前Class物件的介面 |
ClassLoader getClassLoader() | 返回該類的類載入器 |
Constructor[] getConstructors() | 返回一個包含某些Constructor物件的陣列 |
Method getMothed(String name,Class… T) | 返回一個Method物件,此物件的形參型別為paramType |
Field[] getDeclaredFields() | 返回Field物件的一一個陣列 |
獲取Class類的例項
- 若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程式效能最高。
Class clazz = Person.class;
- 已知某個類的例項, 呼叫該例項的getClass()方法獲取Class物件
Class clazz = person.getClass();
- 已知一 個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取,
可能丟擲ClassNotFoundException
Class clazz = Class.forName("demo01 .Student");
-
內建基本資料型別可以直接用類名.Type
-
還可以利用ClassLoader
//class類的建立方式,
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("我是一個:"+person.name);
//Class物件只有一個
//方式一:通過物件獲得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:forName獲得
Class c2 = Class.forName("com.qh.reflection.demo02.Student");
System.out.println(c2.hashCode());
//方式三:通過類名.class獲得
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本內建型別的包裝類都有一個Type屬性
Class<Integer> c4 = Integer.TYPE;
System.out.println(c4); //int
//獲取父類的型別
Class c5 = c1.getSuperclass();
System.out.println(c5);
//獲取該物件的類路徑
System.out.println(c1.getName());
//返回該類的類載入器
System.out.println(c1.getClassLoader());
}
}
哪些型別可以有Class物件
class:外部類,成員(成員內部類,靜態內部類),區域性內部類(匿名內部類。
interface:介面
[]:陣列
enum:列舉
annotation: )註解@interface
primitive type:基本資料型別
void
import java.lang.annotation.ElementType;
//所有型別的Class
public class Test {
public static void main(String[] args) {
Class c1 = Object.class; //類
Class c2 = Comparable.class; //介面
Class c3 = String[].class; //一維陣列
Class c4 = int[][].class; //二維陣列
Class c5 = Override.class; //註解
Class c6 = ElementType.class; //列舉
Class c7 = Integer.class; //基本資料型別
Class c8 = void.class; //void
Class c9 = Class.class; //Class
//快捷鍵,按住Alt用滑鼠可以多行選中
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
//只要元素型別和維度一樣,就是同一個Class
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
類載入過程
當程式主動使用某個類時,如果該類還未被載入到記憶體中,則系統會通過
如下三個步驟來對該類進行初始化。
類的載入與ClassLoader的理解
載入:將class檔案位元組碼內容載入到記憶體中,並將這些靜態資料轉換成方法區的執行時資料 結構, 然 後生成一個代表這個類的java.lang.Class物件.
連結: 將Java類的二進位制程式碼合併到JVM的執行狀態之中的過程。
- 驗證:確保載入的類資訊符合JVM規範,沒有安全方面的問題
- 準備: 正式為類變數(static) 分配記憶體並設定類變數預設初始值的階段,這些記憶體都將在方法區中進行分配。
- 解析:虛擬機器常量池內的符號引用(常量名)替換為直接引用(地址)的過程。
初始化:
- 執行類構造器< clinit> ()方法的過程。類構造器< clinit> ()方法是由編譯期自動收集類中所有類變數的賦值動作和靜態
- 程式碼塊中的語句合併產生的。(類構造器是構造類資訊的,不是構造該類物件的構造器)。
- 當初始化一個類的時候,如果發現其父類還沒有進行初始化,則需要先觸發其父類的初始化。
- 虛擬機器會保證一個類的 ()方法在多執行緒環境中被正確加鎖和同步。
/**
* 分析:
* 1.載入到記憶體,會產生一個類對應的Class物件
* 2.連結,連結結束後 m=0;
* 3.初始化:
* <clinit>(){
* System.out.println("A類靜態程式碼塊初始化");
* m=300;
* m=100;
* }
* m=100;
*/
public class A {
static {
System.out.println("A類靜態程式碼塊初始化");
m=300;
}
/*m = 300
m = 100
*/
static int m=100;
public A(){
System.out.println("A類的無參建構函式初始化");
}
}
//類載入記憶體分析
public class Test {
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
}
}
結果
A類靜態程式碼塊初始化
A類的無參建構函式初始化
100
分析類的初始化
類的主動引用(一定會發生類的初始化)
1.當虛擬機器啟動,先初始化main方法所在的類
2.new一個類的物件
3.呼叫類的靜態成員(除了final常量)和靜態方法.
4.使用java.lang.reflect包的方法對類進行反射呼叫
5.當初始化一個類, 如果其父類沒有被初始化,則先會初始化它的父類
類的被動引用(不會發生類的初始化)
1.當訪問一個靜態域時,只有真正宣告這個域的類才會被初始化。如:當通過子類引用父類 的靜態變數,不會導致子類初始化
2.通過陣列定義類引用,不會觸發此類的初始化
3.引用常量不會觸發 此類的初始化(常量在連結階段就存入呼叫類的常量池中了)
public class Test {
static{
System.out.println("Main類被載入");
}
public static void main(String[] args) throws ClassNotFoundException {
//1.主動引用
//Son son = new Son();
//反射也會產生主動引用
//Class.forName("com.qh.reflection.demo05.Son");
//不會產生類的引用的方法,通過子類引用父類的靜態變數
//System.out.println(Son.b);
//陣列定義類
//Son[] array = new Son[5];
//引用常量
System.out.println(Son.M);
}
}
類載入器的作用
- 類載入的作用:將class檔案位元組碼內容載入到記憶體中,並將這些靜態資料轉換成方法區的執行時資料結構,然後在堆中生成一個代表這個類的java.lang.Class物件作為方法區中類資料的訪問入口。
- 類快取:標準的JavaSE類載入器可以按要求查詢類,但一旦某個類被載入到類載入器中,它將維持載入(快取) 一段時間。 不過JVM垃圾回收機制可以回收這些Class物件
類載入器的作用是用來把類(class)裝在進記憶體的。JVM規範定義瞭如下型別的類載入器
- 引導類載入器:用C++編寫的,是JVM自帶的類載入器負責Java平臺核心庫,用來裝載核心類庫。該載入器無法直接獲取
- 擴充套件類載入器:負責jre/lib/ext目錄下的jar包或 -D java.ext.dirs指定日錄下的jar包裝入工作庫
- 系統類載入器:負責java - classpath或 -D java.class.path所指的目錄下的類與jar包裝入工作,是最常用的載入器
java的核心庫:rt.jar
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//獲取系統類的載入器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//獲取系統類的載入器的父類載入器--->擴充套件類載入器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//獲取擴張類載入器的父類載入器--->根載入器(c/c++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1); //null,無法直接獲取
//測試當前類是哪個載入器載入的
ClassLoader classLoader = Class.forName("com.qh.reflection.demo06.Test").getClassLoader();
System.out.println(classLoader);
//測試JDK內建類是哪個載入器載入的
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1);// null
//如何獲得系統類載入器可以載入的路徑
System.out.println(System.getProperty("java.class.path"));
//雙親委派機制
}
}
雙親委派機制,的確是防止同名包、類與 jdk 中的相沖突,實際上載入類的時候,先通知 appLoader,看 appLoader 是否已經快取,沒有的話,appLoader 又委派給他的父類載入器(extLoader)詢問,看他是不是能已經快取載入,沒有的話,extLoader 又委派他的父類載入器(bootstrapLoader)詢問,BootstrapLoader看是不是自己已快取或者能載入的,有就載入,沒有再返回 extLoader,extLoader 能載入就載入,不能的話再返回給 appLoader 載入,再返回的路中,誰能載入,載入的同時也加快取裡。正是由於不停的找自己父級,所以才有 Parents 載入機制,翻譯過來叫 雙親委派機制。
當某個類載入器需要載入某個.class檔案時,它首先把這個任務委託給他的上級類載入器,遞迴這個操作,如果上級的類載入器沒有載入,自己才會去載入這個類。
獲取執行時類的完整結構
通過反射獲取執行時類的完整結構
Field、Method, Constructor、 Superclass、 Interface、Annotation
//實體類
public class User {
private String name;
private int id;
private int age;
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void show(){
}
private User(String name, int id) {
this.name = name;
this.id = id;
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//獲得類的資訊
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
//獲取User的Class物件
Class c1 = Class.forName("com.qh.reflection.demo07.User");
//獲取類名
String name = c1.getName(); //獲取 包名+類名
String simpleName = c1.getSimpleName(); //獲取 類名
System.out.println(simpleName);
System.out.println(name);
//獲取類中的屬性
Field[] fields = c1.getFields(); //只能獲取public 屬性
Field[] declaredFields = c1.getDeclaredFields(); //能獲取所有的屬性
for(Field f : declaredFields){
System.out.println(f);
}
//獲取指定屬性的值
Field name1 = c1.getDeclaredField("name");
System.out.println(name1);
//獲取類的方法
System.out.println("==============================");
Method[] methods = c1.getMethods(); //獲取本類及其父類的所有public方法
for(Method method: methods){
System.out.println("-->"+method);
}
Method[] declaredMethods = c1.getDeclaredMethods(); //獲取本類的所有方法
for(Method method : declaredMethods){
System.out.println(method);
}
System.out.println("=========================================");
//獲取指定的方法,第二個引數為引數型別的.class,沒有則為null
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
System.out.println("=========================================");
//獲得類的構造器
Constructor[] constructors = c1.getConstructors();// 獲得public構造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) { //獲得所有構造器
System.out.println("##"+constructor);
}
//獲取指定構造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println("指定:"+declaredConstructor);
}
}
在實際的操作中,取得類的資訊的操作程式碼並不會經常開發。
一定要熟悉java.lang.reflect包的作用,反射機制。
如何取得屬性、方法、構造器的名稱,修飾符等。
有了Class物件,能做什麼
建立類的物件:呼叫Class物件的newInstance()方法
- 類必須有一-個無引數的構造器
- 類的構造器的訪問許可權需要足夠
思考? 難道沒有無參的構造器就不能建立物件了嗎?只要在操作的時候明確的呼叫類中的構造器,
並將引數傳遞進去之後,才可以例項化操作。
步驟如下:
1)通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參型別的構造器
2)向構造器的形參中傳遞一個物件陣列進去,裡面包含了構造器中所需的各個引數。
3)通過Constructor例項化物件
呼叫指定的方法
通過反射,呼叫類中的方法,通過Method類完成。
①通過Class類的getMethod(String name,Cas…parameterTypes)方法取得
一個Method物件,並設定此方法操作時所需要的引數型別。
②之後使用Object invgke(Object obj, Object[] args)進行呼叫,並向方法中傳
遞要設定的obj物件的引數資訊。
setAccessible
-
Method和Field、 Constructor物件都有setAccessible方法。
-
setAccessible作用是啟動和禁用訪問安全檢查的開關。
-
引數值為true則指示反射的物件在使用時應該取消Java語言訪問檢查。
-
提高反射的效率。如果程式碼中必須用反射,而該句程式碼需要頻繁的被呼叫,那麼請設定為true。
-
使得原本無法訪問的私有成員也可以訪問
-
-
引數值為false則指示反射的物件應該實施Java語言訪問檢查
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//動態建立物件,通過反射
public class Test {
public static void main(String[] args) throws Exception {
//獲得Class物件
Class c1 = Class.forName("com.qh.reflection.demo08.User");
//建立一個物件
//User user = (User)c1.newInstance();//本質上呼叫了類的無參構造器
//System.out.println(user);
//通過構造器建立物件
//Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
//User jack =(User) constructor.newInstance("jack", 001, 20);
//System.out.println(jack);
//通過反射呼叫普通方法
User user2 = (User)c1.newInstance();
//通過反射獲取一個方法
Method setName = c1.getMethod("setName", String.class);
//invoke 啟用的意思
//(物件,“方法的值”)
//把這個值賦值給哪個物件;
setName.invoke(user2,"jack");
System.out.println(user2.getName());
System.out.println("------------------------------------------");
//通過反射操作屬性
User user3 = (User)c1.newInstance();
//獲取屬性
Field name = c1.getDeclaredField("name");
//不能直接操作私有屬性,我們需要關閉程式的安全檢測,屬性或方法的setAccessible(true);
name.setAccessible(true); //不加,許可權不足
name.set(user3,"jack2");
System.out.println(user3.getName());
}
}
效能對比分析
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析效能問題
public class Test {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Test01();
Test02();
Test03();
}
//普通方式呼叫
public static void Test01(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式執行10億次"+(endTime-startTime)+"ms");
}
//反射方式呼叫
public static void Test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
//獲取方法
Method getName = c1.getMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式執行10億次"+(endTime-startTime)+"ms");
}
//反射方式呼叫,關閉檢測
public static void Test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
//獲取方法
Method getName = c1.getMethod("getName", null);
getName.setAccessible(true);//關閉檢測
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("關閉檢測執行10億次"+(endTime-startTime)+"ms");
}
}
反射操作泛型
- Java採用泛型擦除的機制來引|入泛型, Java中的泛型僅僅是給編譯器javac使用的,確保資料的安全性和免去強制型別轉換問題,但是,一旦編譯完成,所有和泛型有關的型別全部擦除
- 為了通過反射操作這些型別, Java新增了ParameterizedType, GenericArrayType,
TypeVariable和WildcardType幾種型別來代表不能被歸一到Class類中的型別但是又和原始型別齊名的型別. - ParameterizedType :表示一種引數化型別,比如Collection
- GenericArrayType :表示一種元素型別是引數化型別或者型別變數的陣列
- TypeVariable :是各種型別變數的公共父介面
- WildcardType :代表一種萬用字元型別表示式
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class Test {
public void test01(Map<String,User> map , List<User> list){
System.out.println("test01");
}
public Map<String,User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//獲取方法
Method method = Test.class.getMethod("test01", Map.class, List.class);
//獲取泛型的引數資訊
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#"+genericParameterType);
//如果泛型的引數型別屬於引數化型別
if(genericParameterType instanceof ParameterizedType){
//獲得真實的引數資訊
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
method = Test.class.getMethod("test02", null);
//獲取返回值型別
Type genericReturnType = method.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
//獲得真實的引數資訊
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("--"+actualTypeArgument);
}
}
}
}
反射操作註解
瞭解什麼是ORM?
Object relationship Mapping —> 物件關係對映
- 類和表結構對應
- 屬性和欄位對應
- 物件和記錄對應
要求:利用註解和反射完成類和表結構的對映關係
import java.lang.annotation.*;
import java.lang.reflect.Field;
//練習反射操作註解
public class Test {
public static void main(String[] args) throws NoSuchFieldException {
Class c1 = Student.class;
//通過反射獲得註解
Annotation[] declaredAnnotations = c1.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
}
//獲得註解的value的值
TabStudent tabStudent =(TabStudent) c1.getDeclaredAnnotation(TabStudent.class);
String value = tabStudent.value();
System.out.println(value);
//獲得屬性註解的值
Field f = c1.getDeclaredField("name");
FieldStudent declaredAnnotation = f.getDeclaredAnnotation(FieldStudent.class);
System.out.println(declaredAnnotation.columnName());
System.out.println(declaredAnnotation.type());
System.out.println(declaredAnnotation.length());
}
}
@TabStudent("db_student")
class Student{
@FieldStudent(columnName = "db_id",type = "int",length = 10)
private int id;
@FieldStudent(columnName = "db_age",type = "int",length = 10)
private int age;
@FieldStudent(columnName = "db_name",type = "varchar",length = 3)
private String name ;
public Student() {
}
public Student(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//類名的註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TabStudent{
String value();
}
//屬性的註解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldStudent{
String columnName();
String type();
int length();
}
相關文章
- Java註解與反射學習筆記Java反射筆記
- Java學習筆記系列-反射Java筆記反射
- 註解和反射反射
- Java註解和反射Java反射
- Java 註解和反射Java反射
- JAVA核心技術學習筆記--反射Java筆記反射
- Java基礎加強筆記——測試、反射、註解Java筆記反射
- Spring學習筆記2(IOC註解方式&AOP)Spring筆記
- Kubernetes學習筆記(二):Pod、標籤、註解筆記
- java反射之動態代理學習筆記Java反射筆記
- Java反射和註解基本用法Java反射
- 註解和反射Day02反射
- 註解 & 反射反射
- Consul 學習筆記-服務註冊筆記
- 每日註解學習(九)@PostConstruct和@PreConstruct註解Struct
- Java列舉類、註解和反射Java反射
- 我的 golang 學習筆記系列四:反射初識Golang筆記反射
- SAP Fiori Elements 公開課第三單元學習筆記 - OData 和註解深入講解筆記
- Java反射-註解Java反射
- 註解與反射反射
- 小白的學習筆記——eureka註冊中心筆記
- java註解初步學習和使用Java
- Java反射與註解Java反射
- 工作學習筆記(十八)Java中的註釋筆記Java
- GO語言學習筆記-反射篇 Study for Go ! Chapter nine - ReflectGo筆記反射APT
- 暑期自學 Day 08 | Junit,反射,註解(二)反射
- 暑期自學 Day 07 | Junit,反射,註解(一)反射
- Java筆記-反射Java筆記反射
- JAVA-註解(2)-自定義註解及反射註解Java反射
- Go學習筆記-GMP詳解Go筆記
- systemtap和火焰圖學習筆記筆記
- Git和Maven的學習筆記GitMaven筆記
- Node學習筆記 Mongodb 和 Mongoose筆記MongoDB
- numpy的學習筆記\pandas學習筆記筆記
- Spring IOC官方文件學習筆記(十一)之使用JSR 330標準註解Spring筆記JS
- bootstrap-modal.js學習筆記(原始碼註釋)bootJS筆記原始碼
- GObject學習筆記(二)型別建立與註冊GoObject筆記型別
- Java之註解與反射Java反射