目錄
- 注解 java.lang.annotation
- 什么是注解
- 內置注解
- 元注解
- 自定義注解
- 反射 java.Reflection
- 動態語言
- 靜態語言
- 反射概述
- 反射機制應用
- 反射優點和缺點
- 反射相關主要API
- Class類
- 獲取Class類的實體
- 哪些型別可以有Class物件
- Java記憶體分析
- 類加載記憶體分析
- 類的加載與ClassLoader的理解
- 分析類初始化
- 類加載器的作用
- 獲取類的運行時結構
- 動態創建物件并執行
- 創建物件
- 呼叫方法
- setAccessible
- 分析性能問題
- 反射操作泛型
- 反射操作注解
注解 java.lang.annotation
什么是注解
- Annotation是從JDK5.0開始引入的技術,
- Annotation的作用:
- 不是程式本身,可以對程式作出解釋,(這一點和注釋一樣)
- 可以被其他程式(如:編譯器等)讀取,
- Annotation的格式:
- 注解是以"@注解名"在代碼中存在的,還可以添加一些引數值,如:@SuppressWarnings(value="https://www.cnblogs.com/wl3pb/p/unchecked")
- Annotation在哪里使用?
- 可以附加在package,class,method,field等上面,相當于給他們添加了額外的輔助資訊,我們可以通過反射機制編程實作對這些元資料的訪問,
- 可以附加在package,class,method,field等上面,相當于給他們添加了額外的輔助資訊,我們可以通過反射機制編程實作對這些元資料的訪問,
內置注解
- @Override宣告重寫方法
- @Deprecated宣告不推薦使用
- @SuppressWarnings抑制編譯時的警告資訊
元注解
- 元注解的作用就是負責注解其他注解,Java定義了4個標準的meta-annotation型別,他們被用來提供對其他annotation型別作說明,
- 這些型別和它們所支持的類在java.lang.annotation包中可以找到,
- @Target用于描述注解的使用范圍(即:被描述的注解可以用在什么地方,類還是方法等),
- @Retention表示在什么級別該注解還有效,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME),
- @Documented說明該注解將被包含在javadoc中,
- @Inherited說明子類可以繼承父類中的該注解,
自定義注解
- 使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation介面,
- @interface用來宣告一個注解,格式:public @interface 注解名{定義內容},
public @interface Target {
ElementType[] value();
}
- 其中的每一個方法實際上是宣告了一個配置引數,
- 方法的名稱就是引數的名稱,
- 回傳值型別就是引數的型別(回傳值只能是基本型別,Class,String,enum),
- 可以通過default來宣告引數的默認值,
- 如果只有一個引數成員,一般引數名為value,
- 注解元素必須要有值,我們定義注解元素時,經常使用空字串,0作為默認值,
package com.qing.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義注解
*/
public class Demo01 {
//注解如果沒有默認值,就必須給注解賦值
@MyAnnotation1(value = "https://www.cnblogs.com/wl3pb/p/張三豐")
public void test1() {}
//如果只有一個引數,且引數名為value,可以不寫引數名
@MyAnnotation1("張三豐")
public void test2() {}
//注解如果有默認值,可以不賦值
@MyAnnotation2()
public void test3() {}
@MyAnnotation3(name = "張三豐",schools = {"少林寺,武當山"})
public void test4() {}
@MyAnnotation3(name = "張無忌",id = 100,schools = {"冰火島"})
public void test5() {}
}
//如果只有一個引數成員,一般引數名為value
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation1 {
//注解的引數:引數型別 + 引數名();
String value();
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {
//可以通過default來宣告引數的默認值
String value() default "";
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3 {
String name();
String code() default "";
int age() default 0;
int id() default -1;//如果默認值為-1,代表不存在
String[] schools();
String[] wuGong() default {"太極拳","太極劍"};
}
反射 java.Reflection
動態語言
- 是一類在運行時可以改變其結構的語言:例如新的函式、物件、甚至代碼可以被引進,已有的函式可以被洗掉或是其他結構上的變化,通俗的說就是在運行時代碼可以根據某些條件改變自身結構,
- 主要動態語言:Object-C、C#、JavaScript、PHP、Python等,
靜態語言
- 與動態語言相對應的,運行時結構不可變的語言就是靜態語言,如Java、C、C++,
- Java不是動態語言,但Java可以稱之為“準動態語言”,即Java有一定的動態性,我們可以利用反射機制獲得類似動態語言的特性,Java的動態性讓編程的時候更加靈活,
反射概述
- 反射(Reflection)是Java被視為動態語言的關鍵,反射機制允許程式在執行期借助于Reflection API取得任何類的內部資訊,并能直接操作任意物件的內部屬性和方法,
- 加載完類之后,在堆記憶體的方法區中就產生了一個Class型別的物件(一個類只有一個Class物件),這個物件就包含了完整的類的結構資訊,我們可以通過這個物件看到類的結構,這個物件就像一面鏡子,透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射,
反射機制應用
- 在運行時判斷任意一個物件所屬的類,
- 在運行時構造任意一個類的物件,
- 在運行時判斷任意一個類所具有的成員變數和方法,
- 在運行時獲取泛型資訊,
- 在運行時呼叫任意一個物件的成員變數和方法,
- 在運行時處理注解,
- 生成動態代理,
反射優點和缺點
- 優點:
- 可以實作動態創建物件和編譯,體現出很大的靈活性,
- 缺點:
- 對性能有影響,使用反射基本上是一種解釋操作,我們需要告訴JVM,我們希望做什么并且它滿足我們的要求,這類操作總是慢于直接執行相同的操作,
- 對性能有影響,使用反射基本上是一種解釋操作,我們需要告訴JVM,我們希望做什么并且它滿足我們的要求,這類操作總是慢于直接執行相同的操作,
反射相關主要API
- java.lang.Class 代表一個類
- java.lang.reflect.Method 代表類的方法
- java.lang.reflect.Field 代表類的成員變數
- java.lang.reflect.Constructor 代表類的構造器
Class類
- 物件反射后可以得到的資訊:類的屬性、方法和構造器、類實作的介面,
- 對于每個類而言,JRE都為其保留一個不變的Class型別的物件,
- 一個Class物件包含了特定某個結構(class/interface/enum/annotation/primitive type/void/[])的有關資訊,
- Class本身也是一個類,
- Class物件只能由系統建立物件,
- 一個加載的類在JVM中只有一個Class實體,
- 一個Class物件對應的是一個加載到JVM中的一個.class檔案,
- 每個類的實體都會記得自己是由哪個Class實體所生成,
- 通過Class可以完整地得到一個類中的所有被加載的結構,
- Class類是Reflection的根源,針對任何你想動態加載、運行的類,唯有先獲得相應的Class物件,
package com.qing.reflection;
//什么叫反射
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//通過反射獲取類的Class物件
//一個類被加載后,類的整個結構都會被封裝在Class物件中
Class c1 = Class.forName("com.qing.reflection.User");
System.out.println(c1);
//一個類在記憶體中只有一個Class物件,所有它的物件的hashCode值是相同的
Class c2 = Class.forName("com.qing.reflection.User");
Class c3 = Class.forName("com.qing.reflection.User");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
}
}
//物體類
class User {
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
class com.qing.reflection.User
460141958
460141958
460141958
獲取Class類的實體
- 若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程式性能最高,
Class clazz = Person.class;
- 已知某個類的實體,呼叫該實體的getClass()方法獲取Class物件,
Class clazz = person.getClass();
- 已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取,可能拋出ClassNotFoundException,
Class clazz = Class.forName("demo01.Student");
- 內置基本資料型別可以直接用類名.Type,
- 還可以利用ClassLoader,
package com.qing.reflection;
/**
* 測驗Class類的創建方式有哪些
*/
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("這個是:" + person.name);
//方式一:通過物件獲得
Class cl1 = person.getClass();
System.out.println(cl1);
System.out.println(cl1.hashCode());
//方式二:forName獲得
Class cl2 = Class.forName("com.qing.reflection.Student");
System.out.println(cl2);
System.out.println(cl2.hashCode());
//方式三:通過類名.class獲得
Class cl3 = Student.class;
System.out.println(cl3);
System.out.println(cl3.hashCode());
//方式四:基本資料型別的包裝類都有一個TYPE屬性
Class cl4 = Integer.TYPE;
System.out.println(cl4);
//獲得父型別別
Class cl5 = cl1.getSuperclass();
System.out.println(cl5);
}
}
class Person {
public String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person {
public Student() {
this.name = "學生";
}
}
class Teacher extends Person {
public Teacher() {
this.name = "老師";
}
}
這個是:學生
class com.qing.reflection.Student
460141958
class com.qing.reflection.Student
460141958
class com.qing.reflection.Student
460141958
int
class com.qing.reflection.Person
哪些型別可以有Class物件
- class:外部類,成員類(成員內部類,靜態內部類),區域內部類,匿名內部類,
- interface:介面,
- []:陣列,
- enum:列舉,
- annotation:注解@interface,
- primitive type:基本資料型別,
- void,
package com.qing.reflection;
import java.lang.annotation.ElementType;
/**
* 所有型別的Class
*/
public class Test03 {
public static void main(String[] args) {
Class c1 = Object.class;//類
Class c2 = Comparable.class;//介面
Class c3 = String[].class;//陣列
Class c4 = int[].class;//陣列
Class c5 = double[].class;//陣列
Class c6 = int[][].class;//二維陣列
Class c7 = Override.class;//注解
Class c8 = ElementType.class;//列舉
Class c9 = Integer.class;//包裝類
Class c10 = void.class;//void
Class c11 = Class.class;//Class
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);
System.out.println(c10);
System.out.println(c11);
}
}
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [I
class [D
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
Java記憶體分析

類加載記憶體分析
- 當程式主動使用某個類時,如果該類還未被加載到記憶體中,則系統會通過如下三個步驟來對該類進行初始化,

類的加載與ClassLoader的理解
- 加載:將class檔案位元組碼內容加載到記憶體中,并將這些靜態資料轉換成方法區的運行時資料結構,然后生成一個代表這個類的java.lang.Class物件,
- 鏈接:將Java類的二進制代碼合并到JVM的運行狀態之中的程序,
- 驗證:確保加載的類資訊符合JVM規范,沒有安全方面的問題,
- 準備:正式為類變數(static)分配記憶體并設定類變數默認初始值的階段,這些記憶體都將在方法區中進行分配,
- 決議:虛擬機常量池內的符號參考(常量名)替換為直接參考(地址)的程序,
- 初始化:
- 執行類構造器
()方法的程序,類構造器 ()方法是由編譯期自動收集類中所有類變數的賦值動作和靜態代碼塊中的陳述句合并產生的,(注:類構造器是構造類資訊的,不是構造該類物件的構造器) - 當初始化一個類的時候,如果發現其父類還沒有進行初始化,則需要先觸發其父類的初始化,
- 虛擬機會保證一個類的
()方法在多執行緒環境中被正確的加鎖和同步,
- 執行類構造器
package com.qing.reflection;
/**
* 測驗類的加載程序
*/
public class Test04 {
public static void main(String[] args) {
System.out.println("main方法執行");
System.out.println("main:" + A.m);
A a = new A();
System.out.println(a.m);
/*
1.類加載到記憶體,會產生一個類對應的Class物件
2.類鏈接,鏈接結束后 m = 0
3.類初始化
<clinit>(){
System.out.println("靜態代碼塊" + A.m);
System.out.println("A類靜態代碼塊初始化");
m = 300;
System.out.println(A.m);
m = 100;
}
m = 100;
4.物件初始化
m = 200;
*/
}
}
class A {
static {
System.out.println("靜態代碼塊" + A.m);
System.out.println("A類靜態代碼塊初始化");
m = 300;
System.out.println(A.m);
}
static int m = 100;
public A() {
System.out.println("A類的無參構造初始化");
m = 200;
System.out.println(m);
}
}
main方法執行
靜態代碼塊0
A類靜態代碼塊初始化
300
main:100
A類的無參構造初始化
200
200
分析類初始化
- 類的主動參考(一定會發生類的初始化)
- 當虛擬機啟動,先初始化main方法所在的類,
- new一個類的物件,
- 呼叫類的靜態成員(除了final常量)和靜態方法,
- 使用java.lang.reflect包的方法對類進行反射呼叫,
- 當初始化一個類,如果其父類沒有被初始化,則會先初始化它的父類,
- 類的被動參考(不會發生類的初始化)
- 當訪問一個靜態域時,只有真正宣告這個域的類才會被初始化,如:當通過子類參考父類的靜態變數,不會導致子類初始化,
- 通過陣列定義類參考,不會觸發此類的初始化,
- 參考常量不會觸發此類的初始化(常量在鏈接階段就存入呼叫類的常量池中了),
package com.qing.reflection;
/**
* 測驗類什么時候會初始化
*/
public class Test05 {
static {
System.out.println("Main類被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
//1.主動參考
// Son son = new Son();
//反射也會產生主動參考
// Class.forName("com.qing.reflection.Son");/
//不會產生類的初始化的方法
System.out.println(Son.f);
Son[] sons = new Son[5];
System.out.println(Son.S);
}
}
class Father {
static int f = 1;
static {
System.out.println("父類被加載");
}
}
class Son extends Father {
static {
System.out.println("子類被加載");
s = 11;
}
static int s = 10;
static final int S = 100;
}
類加載器的作用
- 類加載的作用:將class檔案位元組碼內容加載到記憶體中,并將這些靜態資料轉換成方法區的運行時資料結構,然后在堆中生成一個代表這個類的java.lang.class物件,作為方法區中類資料的訪問入口,
- 類快取:標準的JavaSE類加載器可以按要求查找類,但一旦某個類被加載到類加載器中,它將維持加載(快取)一段時間,不過JVM垃圾回識訓制可以回收這些Class物件,

- 類加載器作用是用來把類(class)裝載進記憶體的,JVM規范定義了如下型別的類的加載器,


package com.qing.reflection;
public class Test06 {
public static void main(String[] args) {
//獲取系統類的加載器
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);
//測驗當前類是哪個加載器加載的
ClassLoader classLoader = Test06.class.getClassLoader();
System.out.println(classLoader);
//測驗JDK內置類是哪個加載器加載的
classLoader = Object.class.getClassLoader();
System.out.println(classLoader);
//如何獲得系統類加載器可以加載的路徑
System.out.println(System.getProperty("java.class.path"));
/*
D:\environment\Java\jdk1.8\jre\lib\charsets.jar;
D:\environment\Java\jdk1.8\jre\lib\deploy.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\access-bridge-64.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\cldrdata.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\dnsns.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\jaccess.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\jfxrt.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\localedata.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\nashorn.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\sunec.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\sunjce_provider.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\sunmscapi.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\sunpkcs11.jar;
D:\environment\Java\jdk1.8\jre\lib\ext\zipfs.jar;
D:\environment\Java\jdk1.8\jre\lib\javaws.jar;
D:\environment\Java\jdk1.8\jre\lib\jce.jar;
D:\environment\Java\jdk1.8\jre\lib\jfr.jar;
D:\environment\Java\jdk1.8\jre\lib\jfxswt.jar;
D:\environment\Java\jdk1.8\jre\lib\jsse.jar;
D:\environment\Java\jdk1.8\jre\lib\management-agent.jar;
D:\environment\Java\jdk1.8\jre\lib\plugin.jar;
D:\environment\Java\jdk1.8\jre\lib\resources.jar;
D:\environment\Java\jdk1.8\jre\lib\rt.jar;
D:\code\JavaSE\out\production\注解和反射;
D:\program files\JetBrains\IntelliJ IDEA 2018.2.5\lib\idea_rt.jar
*/
}
}
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
獲取類的運行時結構
- 通過反射獲取運行時類的完整結構:Field/Method/Constructor/SuperClass/Interface/Annotation,
package com.qing.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 獲取類的資訊
*/
public class Test07 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
User user = new User();
Class c1 = user.getClass();
//獲取類的名字
System.out.println(c1.getName());//包名+類名
System.out.println(c1.getSimpleName());//類名
//獲得類的屬性
System.out.println("==============");
Field[] fields = c1.getFields();//只能獲得public屬性
for (Field field : fields) {
System.out.println(field);
}
System.out.println("==============");
fields = c1.getDeclaredFields();//全部屬性
for (Field field : fields) {
System.out.println(field);
}
//獲得類的指定屬性
System.out.println("================");
System.out.println(c1.getDeclaredField("name"));
//獲得類的方法
System.out.println("================");
Method[] methods = c1.getMethods();//本類及其父類的public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("===============");
methods = c1.getDeclaredMethods();//本類的所有方法
for (Method method : methods) {
System.out.println(method);
}
//獲得指定的方法
System.out.println("=====================");
System.out.println(c1.getDeclaredMethod("getName"));
System.out.println(c1.getDeclaredMethod("setName",String.class));
System.out.println(c1.getDeclaredMethod("setId", int.class));
//獲得類的構造器
System.out.println("=======================");
Constructor[] constructors = c1.getConstructors();//public構造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("===============================");
constructors = c1.getDeclaredConstructors();//所有構造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//獲得指定的構造器
System.out.println("========================");
System.out.println(c1.getDeclaredConstructor(int.class,String.class,int.class));
}
}
com.qing.reflection.User
User
==============
public int com.qing.reflection.User.id
==============
public int com.qing.reflection.User.id
private java.lang.String com.qing.reflection.User.name
private int com.qing.reflection.User.age
================
private java.lang.String com.qing.reflection.User.name
================
public java.lang.String com.qing.reflection.User.toString()
public java.lang.String com.qing.reflection.User.getName()
public int com.qing.reflection.User.getId()
public void com.qing.reflection.User.setName(java.lang.String)
public void com.qing.reflection.User.setId(int)
public int com.qing.reflection.User.getAge()
public void com.qing.reflection.User.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
===============
public java.lang.String com.qing.reflection.User.toString()
public java.lang.String com.qing.reflection.User.getName()
public int com.qing.reflection.User.getId()
public void com.qing.reflection.User.setName(java.lang.String)
private void com.qing.reflection.User.test()
public void com.qing.reflection.User.setId(int)
public int com.qing.reflection.User.getAge()
public void com.qing.reflection.User.setAge(int)
=====================
public java.lang.String com.qing.reflection.User.getName()
public void com.qing.reflection.User.setName(java.lang.String)
public void com.qing.reflection.User.setId(int)
=======================
public com.qing.reflection.User()
public com.qing.reflection.User(int,java.lang.String,int)
===============================
public com.qing.reflection.User()
public com.qing.reflection.User(int,java.lang.String,int)
========================
public com.qing.reflection.User(int,java.lang.String,int)
動態創建物件并執行
創建物件
- 呼叫Class物件的newInstance()方法,
- 類必須有一個無參構造器,
- 類的構造器的訪問權限需要足夠,
- 呼叫構造器物件的newInstance()方法,
- 通過Class類的getDeclaredConstructor(Class...parameterTypes)取得本類的指定形參型別的構造器,
- 向構造器的形參中傳遞一個物件陣列進去,里面包含了構造器中所需的各個引數,
- 通過Constructor實體化物件,
呼叫方法
- 通過反射,呼叫類中的方法,通過Method類完成,
- 通過Class類的getMethod(String name,Class...parameterTypes)方法取得一個Method物件,并設定此方法操作時所需要的引數型別,
- 之后使用invoke(Object obj,Object[] args)進行呼叫,并向方法中傳遞要設定的obj物件的引數資訊,
- Object obj為物件,Objcet[] args為引數,
- 原方法若為靜態方法,物件可為null,
- 原方法若沒有引數,引數為null,
- invoke方法的回傳值為方法的回傳值,若原方法無回傳值,此時回傳null,
- 原方法宣告為private,則需要在呼叫invoke()方法前,顯式呼叫方法物件的setAccessible(true)方法,將可訪問private的方法,
setAccessible
- Method/Field/Constructor物件都有setAccessible()方法,
- setAccessible作用是啟動和禁用訪問安全檢查的開關,
- 引數值為true則指示反射的物件在使用時應該取消Java語言訪問檢查,
- 提高反射的效率,如果代碼中必須用反射,而該句代碼需要頻繁的被呼叫,那么請設定為true,
- 使得原本無法訪問的私有成員也可以訪問,
- 引數值為false則指示反射的物件應該實施Java語言訪問檢查,默認為false,
package com.qing.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 動態的創建物件,通過反射
*/
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//獲得Class物件
Class c1 = Class.forName("com.qing.reflection.User");
//創建物件,本質是呼叫了類的無參構造器
User user = (User)c1.newInstance();
System.out.println(user);
//通過構造器創建物件
Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
User user2 = (User)constructor.newInstance(1, "張三豐", 300);
System.out.println(user2);
//通過反射呼叫普通方法
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user,"太極");
System.out.println(user);
//通過反射操作屬性
Field name = c1.getDeclaredField("name");
//不能直接操作私有屬性,需要關閉程式的安全檢測,屬性或方法的setAccessible(true)
name.setAccessible(true);
name.set(user,"太極拳");
System.out.println(user);
}
}
User{id=0, name='null', age=0}
User{id=1, name='張三豐', age=300}
User{id=0, name='太極', age=0}
User{id=0, name='太極拳', age=0}
分析性能問題
package com.qing.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 分析性能問題
*/
public class Test09 {
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 < 1000000000; 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");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
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");
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式并關閉安全檢查執行10億次:" + (endTime-startTime) + "ms");
}
}
普通方式執行10億次:9ms
反射方式執行10億次:6463ms
反射方式并關閉安全檢查執行10億次:3728ms
反射操作泛型
- Java采用泛型擦除的機制來引入泛型,Java中的泛型僅僅是給編譯器javac使用的,確保資料的安全性和免去強制型別轉換問題,但是,一旦編譯完成,所有和泛型有關的型別全部擦除,
- 為了通過反射操作這些型別,Java新增了幾種型別來代表不能被歸一到Class類中的型別但是又和原始型別齊名的型別,
- ParameterizedType:表示一種引數化型別,比如Collection
, - GenericArrayType:表示一種元素型別是引數化型別或者型別變數的陣列型別,
- TypeVariable;是各種型別變數的公共父介面,
- WildcardType:代表一種通配符型別運算式,
- ParameterizedType:表示一種引數化型別,比如Collection
package com.qing.reflection;
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 Test10 {
public static void main(String[] args) throws NoSuchMethodException {
Method test01 = Test10.class.getMethod("test01", Map.class, List.class);
//獲得泛型引數型別
Type[] genericParameterTypes = test01.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 test02 = Test10.class.getMethod("test02");
//獲得泛型回傳值型別
Type genericReturnType = test02.getGenericReturnType();
System.out.println(genericReturnType);
//如果泛型回傳值型別屬于引數化型別,強轉為引數化型別
if (genericReturnType instanceof ParameterizedType) {
//獲得泛型真實回傳值型別
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
public void test01(Map<String,User> map, List list) {
System.out.println("test01");
}
public Map<String,User> test02() {
System.out.println("test02");
return null;
}
}
java.util.Map<java.lang.String, com.qing.reflection.User>
class java.lang.String
class com.qing.reflection.User
interface java.util.List
java.util.Map<java.lang.String, com.qing.reflection.User>
class java.lang.String
class com.qing.reflection.User
反射操作注解
package com.qing.reflection;
import java.lang.annotation.*;
/**
* 反射操作注解
*/
public class Test11 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.qing.reflection.Student2");
//通過反射獲得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//獲得注解的值
Table table = (Table) c1.getAnnotation(Table.class);
System.out.println(table.value());
java.lang.reflect.Field id = c1.getDeclaredField("id");
Field field = (Field) id.getAnnotation(Field.class);
System.out.println(field.columnName());
System.out.println(field.type());
System.out.println(field.length());
}
}
@Table("db_student")
class Student2 {
@Field(columnName = "student_id",type = "int",length = 10)
private int id;
@Field(columnName = "student_age",type = "int",length = 5)
private int age;
@Field(columnName = "student_name",type = "varchar",length = 255)
private String name;
public Student2() {
}
public Student2(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 "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
/**
* 類名的注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
/**
* 屬性的注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field {
String columnName();
String type();
int length();
}
@com.qing.reflection.Table(value=https://www.cnblogs.com/wl3pb/p/db_student)
db_student
student_id
int
10
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/241701.html
標籤:Java
上一篇:你好,Spring!
