標籤:記憶體回收 原因 public dep 理解 ati 泛型使用 protect nat
反射的基本概念
如果正常的情況下,如果使用一個類,則必須按照如下的步驟操作:
-
- 使用import 匯入類所在的包;(類:java.lang.Class)
- 明確的使用類名稱或借口名稱定義對象;
- 通過關鍵字new進行類對象執行個體化;(構造方法:java.lang.reflect.Constructor);
- 產生對象可以使用“對象.屬性”進行類中屬性的調用(屬性:java.lang.reflect.Field);
- 通過“對象.方法()”調用類中方法(方法:java.lang.reflect.Method);
反射過程不需要有明確類型的對象,所有的對象使用Object表示
1. 可以直接使用Object與反射機制的混合調用類中的方法。
Object類中的所有方法以及每一個方法使用上的注意事項:
- 對象複製:protected Object clone?() throws CloneNotSupportedException 建立並返回此對象的副本。 “複製”的精確含義可能取決於對象的類。
- 為什麼複製方法返回的是Object? 答:因為複製方法可能針對所有類對象使用,為了統一參數用Object
- 複製對象所在的類一定要實現java.lang.Cloneable介面而子類只需要繼續調用Object 的複製方法就可以成功實現複製操作;
- 對象輸出:public String toString?() 返回對象的字串表示形式。
- 直接輸出對象時會預設調用toString()方法
- 原因:由於平時我們會直接System.out.println();來直接輸出對象,那麼我們開啟源碼看一下為什麼會預設調用toString()方法
在printStream類中找到print輸出方法 如下
public void print(Object obj) {
write(String.valueOf(obj));
}
可以看到他在輸出的時候調用了String的valueOf方法,下面開啟valueOf方法源碼
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}從中我們可以看到如果傳入的對象不為null的話就會自動的調用toString()方法然後返回
- 對象比較:public boolean equals?(Object obj) 指示一些其他對象是否等於此。
- 有哪些時候會隱式調用此方法??
- 當我們儲存Set集合時,會依靠hashCode()和equals()判斷對象是否重複;
- 取得對象的hash碼:public boolean equals?(Object obj) 指示一些其他對象是否等於此。
- 可以理解為每一個對象的唯一編碼,比較時會先判斷編碼是否相同,然後再調用equals方法判斷是否相同
- 取得Class類對象:public final Class<?> getClass?() 返回此
Object的運行時類。
- 通過一個已經執行個體化好的對象進行對象的反射操作;
- 線程等待:public final void wait?() throws InterruptedException 導致當前線程等到另一個線程調用該對象的
notify()方法或notifyAll()方法。 換句話說,這個方法的行為就好像簡單地執行調用wait(0) 。
- 執行到此代碼時線程要等待執行,直到執行
notify()或者notifyAll()方法來喚醒線程;
- 一個線程喚醒:public final void notify?() 喚醒正在等待對象監視器的單個線程。
- 全部線程喚醒:public final void notifyAll?() 喚醒正在等待對象監視器的所有線程。
- 記憶體回收前釋放:protected void finalize?() throws Throwable 已淘汰。 定稿機制本質上是有問題的。 定稿可能導致效能問題,死結和掛起。
Class類
class類是整個反射的操作源頭,而類的定義如下:
public final class Class<T> //反射的泛型幾乎無用,使用的時候就使用“?”extends Objectimplements Serializable, GenericDeclaration, Type, AnnotatedElement
如果想要使用Class類進行操作,那麼必須首先產生Class類的執行個體化對象,而有三種方法可以去的Claas類的執行個體化對象
-
- Object類提供了一個返回Class類對象的方法:public final Class<?> getClass?();
- 利用“類.class”取得,日後建的最多的就是在Hibernate上;
- 利用Class類的static方法取得,public static Class<?> forName?(String className) throws ClassNotFoundException 返回與給定字串名稱的類或介面相關聯的
Class對象。
如果是程式設計人員,使用最多的方法一定是forName()方法,但是如果是使用者會使用“類.class”。工廠設計模式最好利用反射機制來解決耦合問題。
利用反射執行個體化對象
Class類如果使用了forName()方法之後,就可以使用Class類定義的newInstance()方法預設去調用類之中的無參構造器進行操作
public T newInstance?() throws InstantiationException, IllegalAccessException,此泛型使用不到
代碼示範: 在這裡是不能接受的了這個傳回值的,
這裡就是解決上面錯誤的代碼實現: 從中我們就可以看到我們不一定非要使用new執行個體化對象,只要我們有一個類的完整名稱也可以執行個體化對象
public class R { public static void main(String[] args) throws Exception { Class<?> cls = Class.forName("test.Student"); //jdk 1.9 開始直接使用的newInstance()方法已經過時,可以使用下面的方式來調用newInstance()方法 //相當於關鍵字new執行個體化對象。等價於 Object newInstance = new Student(); Object newInstance = cls.getDeclaredConstructor().newInstance(); }}class Student{ public Student() { System.out.println("構造方法Student"); } }
執行結果:構造方法Student
但是如果使用反射執行個體化對象,必須要求類中存在有無參構造方法,因為newInstance()方法只能找到無參。如果沒有無參建構函式如下:
Exception in thread "main" java.lang.NoSuchMethodException:
如果想找到無參構造怎麼辦?操作構造方法
操作構造方法:
為瞭解決NoSuchMethodException錯誤,這個時候這能取得類之中的構造方法,傳遞所需要的參數後才能使用。
在Class類裡面定義了可以取得一個類中的構造方法的操作:
-
- public Constructor<T> getConstructor?(Class<?>... parameterTypes) (重點使用)
throws NoSuchMethodException, SecurityException
返回一個Constructor對象,及時取得類中制定參數的構造,該對象反映由此Class對象表示的類的指定公用建構函式。
public Class<?>[] getDeclaredClasses?() throws SecurityException
返回一個Class對象的數組,就是全部構造,反映了所有被聲明為由這個Class對象表示的類的成員的類和介面。
代碼示範:取得String中的全部構造方法。
import java.lang.reflect.Constructor;public class GetStringConstructor { public static void main(String[] args) throws Exception { Class<?> forName = Class.forName("java.lang.String"); Constructor<?>[] constructors = forName.getConstructors();//得到所有構造 for (int i = 0; i < constructors.length; i++) { System.out.println(constructors[i]); } }}
執行結果:
public java.lang.String(byte[])
public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
public java.lang.String(char[],int,int)
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String()
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)
public java.lang.String(int[],int,int
所以如果現在想要進行制定構造方法的調用,就必須將關注點放在Contructor類中。
public T newInstance?(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException 使用由此Constructor對象表示的建構函式,使用指定的初始化參數建立和初始化建構函式的聲明類的新執行個體。
代碼實現:執行個體化剛才的Student對象
import java.lang.reflect.Constructor;
class Student{
public Student(String str) {
System.out.println("構造方法Student: "+str);
}
}public class GetStringConstructor { public static void main(String[] args) throws Exception { Class<?> forName = Class.forName("test.Student"); Constructor<?> constructors = forName.getConstructor(String.class);//從這可以看到要與想調用的構造方法的參數類型一直才可以 constructors.newInstance("純菜鳥-java-反射"); }}
執行結果:構造方法Student: 純菜鳥-java-反射 time:40.00
分析簡單java類與反射的聯絡
利用反射解決servlet代碼過多的問題
用反射來解決原廠模式,代理設計模式的操作
動態代理設計模式,CGLIB實現的動態代理設計模式
使用Annotion編寫註解操作
java--反射