Java不懂反射,和鹹魚有什麼區別啊!
Java反射的功能非常之強大,能夠深入的理解其思想,對自己的開發能力將有非常大的提高。
反射概述
Reflection(反射)是Java被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API取得任何類的內部資訊,並能直接操作任意物件的內部屬性及方法。
在這裡還是要推薦下我自己建的Java學習裙:574加上253再加上075,群裡都是學Java開發的,如果你正在學習Java ,小編歡迎你加入,大家都是軟體開發黨,不定期分享乾貨(只有Java軟體開發相關的),包括我自己整理的一份2018最新的Java進階資料和高階開發教程,歡迎進階中和進想深入java的小夥伴
Java反射機制主要提供了以下功能:
· 在執行時構造任意一個類的物件
· 在執行時獲取任意一個類所具有的成員變數和方法
· 在執行時呼叫任意一個物件的方法(屬性)
· 生成動態代理
Class 是一個類; 一個描述類的類.
封裝了描述方法的 Method,
描述欄位的 Filed,
描述構造器的 Constructor 等屬性.
獲取Class物件的三種方式
1.通過類名獲取 類名.class
2.通過物件獲取 物件名.getClass()
3.通過全類名獲取 Class.forName(全類名)
public class ReflectionTest {
@Test
public void testClass() throws ClassNotFoundException {
Class clazz = null;
clazz = Person.class;
//這種方式是用在傳進來一個物件,卻不知道物件型別的時候使用
Person person = new Person();
clazz = person.getClass();
//上面這個例子的意義不大,因為已經知道person型別是Person類,再這樣寫就沒有必要了
//如果傳進來是一個Object類,這種做法就是應該的
Object obj = new Person();
clazz = obj.getClass();
//一般框架開發中這種用的比較多,因為配置檔案中一般配的都是全類名,通過這種方式可以得到Class例項
String className=" com.atguigu.java.fanshe.Person";
clazz = Class.forName(className);
//字串的例子
clazz = String.class;
clazz = “javaTest”.getClass();
clazz = Class.forName(“java.lang.String”);
System.out.println();
}
}
反射中最常用的幾個類:
Method
Field
Constructor
Annotation
如何描述方法-Method
public class ReflectionTest {
@Test
public void testMethod() throws Exception{
Class clazz = Class.forName(“com.atguigu.java.fanshe.Person”);
//
// 1.1 獲取取clazz對應類中的所有方法–方法陣列(一)
// 不能獲取private方法,且獲取從父類繼承來的所有方法
Method[] methods = clazz.getMethods();
for(Method method:methods){
System.out.print(" "+method.getName());
}
System.out.println();
//
// 1.2.獲取所有方法,包括私有方法 --方法陣列(二)
// 所有宣告的方法,都可以獲取到,且只獲取當前類的方法
methods = clazz.getDeclaredMethods();
for(Method method:methods){
System.out.print(" "+method.getName());
}
System.out.println();
// 1.3.獲取指定的方法
// 需要引數名稱和引數列表,無參則不需要寫
// 對於方法public void setName(String name) { }
Method method = clazz.getDeclaredMethod(“setName”, String.class);
System.out.println(method);
// 而對於方法public void setAge(int age) { }
method = clazz.getDeclaredMethod(“setAge”, Integer.class);
System.out.println(method);
// 這樣寫是獲取不到的,如果方法的引數型別是int型
// 如果方法用於反射,那麼要麼int型別寫成Integer: public void setAge(Integer age) { }
// 要麼獲取方法的引數寫成int.class
//
// invoke第一個引數表示執行哪個物件的方法,剩下的引數是執行方法時需要傳入的引數
Object obje = clazz.newInstance();
method.invoke(obje,2);
//如果一個方法是私有方法,第三步是可以獲取到的,但是這一步卻不能執行
//私有方法的執行,必須在呼叫invoke之前加上一句method.setAccessible(true);
}
}
如何描述欄位-Field
@Test
public void testField() throws Exception{
String className = “com.atguigu.java.fanshe.Person”;
Class clazz = Class.forName(className);
// 1.1 獲取所有欄位 – 欄位陣列
// 可以獲取公用和私有的所有欄位,但不能獲取父類欄位
Field[] fields = clazz.getDeclaredFields();
for(Field field: fields){
System.out.print(" "+ field.getName());
}
System.out.println();
// 1.2獲取指定欄位
Field field = clazz.getDeclaredField(“name”);
System.out.println(field.getName());
Person person = new Person(“ABC”,12);
// 2.1獲取指定物件的指定欄位的值
Object val = field.get(person);
System.out.println(val);
// 2.2設定指定物件的指定物件Field值
field.set(person, “DEF”);
System.out.println(person.getName());
// 2.3如果欄位是私有的,不管是讀值還是寫值,都必須先呼叫setAccessible(true)方法
// 比如Person類中,欄位name欄位是公用的,age是私有的
field = clazz.getDeclaredField(“age”);
field.setAccessible(true);
System.out.println(field.get(person));
}
如何描述構造器-Constructor
@Test
public void testConstructor() throws Exception{
String className = “com.atguigu.java.fanshe.Person”;
Class clazz = (Class) Class.forName(className);
//1. 獲取 Constructor 物件
// 1.1 獲取全部
Constructor [] constructors =
(Constructor[]) Class.forName(className).getConstructors();
for(Constructor constructor: constructors){
System.out.println(constructor);
}
// 1.2獲取某一個,需要引數列表
Constructor constructor = clazz.getConstructor(String.class, int.class);
System.out.println(constructor);
//2. 呼叫構造器的 newInstance() 方法建立物件
Object obj = constructor.newInstance(“zhagn”, 1);
}
如何描述註解 – Annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
public @interface AgeValidator {
public int min();
public int max();
}
反射小結
- Class: 是一個類; 一個描述類的類.
封裝了描述方法的 Method,
描述欄位的 Filed,
描述構造器的 Constructor 等屬性.
- 如何得到 Class 物件:
2.1 Person.class
2.2 person.getClass()
2.3 Class.forName(“com.atguigu.javase.Person”)
- 關於 Method:
3.1 如何獲取 Method:
1). getDeclaredMethods: 得到 Method 的陣列.
2). getDeclaredMethod(String methondName, Class … parameterTypes)
3.2 如何呼叫 Method
1). 如果方法時 private 修飾的, 需要先呼叫 Method 的 setAccessible(true), 使其變為可訪問
2). method.invoke(obj, Object … args);
- 關於 Field:
4.1 如何獲取 Field: getField(String fieldName)
4.2 如何獲取 Field 的值:
1). setAccessible(true)
2). field.get(Object obj)
4.3 如何設定 Field 的值:
field.set(Obejct obj, Object val)
- 瞭解 Constructor 和 Annotation
ClassLoader
類載入的順序
public class ReflectionTest {
@Test
public void testClassLoader() throws ClassNotFoundException, FileNotFoundException{
//1. 獲取一個系統的類載入器(可以獲取,當前這個類PeflectTest就是它載入的)
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
//2. 獲取系統類載入器的父類載入器(擴充套件類載入器,可以獲取).
classLoader = classLoader.getParent();
System.out.println(classLoader);
//3. 獲取擴充套件類載入器的父類載入器(引導類載入器,不可獲取).
classLoader = classLoader.getParent();
System.out.println(classLoader);
//4. 測試當前類由哪個類載入器進行載入(系統類載入器):
classLoader = Class.forName(“com.atguigu.java.fanshe.ReflectionTest”)
.getClassLoader();
System.out.println(classLoader);
//5. 測試 JDK 提供的 Object 類由哪個類載入器負責載入(引導類)
classLoader = Class.forName(“java.lang.Object”)
.getClassLoader();
System.out.println(classLoader);
}
}
//結果:
//null
//null