前言:
?相信很多人都知道反射可以說是Java中最強(qiáng)大的技術(shù)了,,它可以做的事情太多太多,,很多優(yōu)秀的開源框架都是通過反射完成的,比如最初的很多注解框架,,后來因?yàn)閖ava反射影響性能,,所以被運(yùn)行時(shí)注解APT替代了,java反射有個(gè)開源框架jOOR相信很多人都用過,,不過我們還是要學(xué)習(xí)反射的基礎(chǔ)語法,,這樣才能自己寫出優(yōu)秀的框架,當(dāng)然這里所講的反射技術(shù),,是學(xué)習(xí)Android插件化技術(shù),、Hook技術(shù)等必不可少的!
概述:
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,,對(duì)于任意一個(gè)類,,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,,都能夠調(diào)用它的任意一個(gè)方法和屬性,;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java語言的反射機(jī)制。
要想解剖一個(gè)類,必須先要獲取到該類的字節(jié)碼文件對(duì)象,。而解剖使用的就是Class類中的方法.所以先要獲取到每一個(gè)字節(jié)碼文件對(duì)應(yīng)的Class類型的對(duì)象.
以上的總結(jié)就是什么是反射
反射就是把java類中的各種成分映射成一個(gè)個(gè)的Java對(duì)象
例如:一個(gè)類有:成員變量,、方法、構(gòu)造方法,、包等等信息,,利用反射技術(shù)可以對(duì)一個(gè)類進(jìn)行解剖,把個(gè)個(gè)組成部分映射成一個(gè)個(gè)對(duì)象,。(其實(shí):一個(gè)類中這些成員方法,、構(gòu)造方法、在加入類中都有一個(gè)類來描述)
如圖是類的正常加載過程:反射的原理在與class對(duì)象,。
熟悉一下加載的時(shí)候:Class對(duì)象的由來是將class文件讀入內(nèi)存,,并為之創(chuàng)建一個(gè)Class對(duì)象。
主要作用
通過反射可以使程序代碼訪問裝載到JVM 中的類的內(nèi)部信息,,獲取已裝載類的屬性信息,,獲取已裝載類的方法,獲取已裝載類的構(gòu)造方法信息
常用方法
(1)創(chuàng)建Student類
package cn.tedu.reflection;
//測試 反射
public class Student {
public String name = "皮皮霞";
public int age = 22 ;
//提供構(gòu)造方法-右鍵-generate...constructor...
public Student() {
}
public Student(String name) {
this.name = name;
}
public Student(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
`public void show(){
System.out.println("show()...");
}
public void test(String n){
System.out.println("test()..."+n);
}
//為了能查看屬性值,而不是地址值,提供重寫的toString()
//右鍵-generate...toString()-ok
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
(2)創(chuàng)建測試類
package cn.tedu.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
//測試 反射
public class Test1_Reflect {
public static void main(String[] args) throws Exception {
//method();//通過反射的技術(shù),獲取Class對(duì)象
// method2();//通過反射的技術(shù),獲取類中的所有構(gòu)造方法
// method3();//通過反射的技術(shù),獲取成員方法
// method4();//通過反射的技術(shù),獲取成員變量
method5();//通過反射的技術(shù),創(chuàng)建實(shí)例
}
//通過反射的技術(shù),創(chuàng)建實(shí)例
private static void method5() throws Exception {
//1,獲取Class對(duì)象
Class<Student> clazz = Student.class;
//2,創(chuàng)建實(shí)例
//newInstance()--會(huì)觸發(fā)構(gòu)造方法--觸發(fā)無參構(gòu)造
Student s = clazz.newInstance();
//s = Student{name='皮皮霞', age=22}
System.out.println("s = " + s);
//3,需求:可以觸發(fā)含參構(gòu)造嗎?可以-但是你得指定想要觸發(fā)哪個(gè)含參構(gòu)造
// --參數(shù)是class對(duì)象類型,和含參構(gòu)造的參數(shù)類型匹配
//public Student(String name){} -- new Student("jack");
Constructor<Student> c = clazz.getConstructor(String.class);
Student s2 = c.newInstance("jack");
//s2 = Student{name='jack', age=22}
System.out.println("s2 = " + s2);
}
//通過反射的技術(shù),獲取成員變量
private static void method4() throws ClassNotFoundException {
//1,獲取Class對(duì)象
Class<?> clazz = Class.forName("cn.tedu.reflection.Student");
//2,獲取成員變量--!!!!只能獲取public的!!!!
Field[] fs = clazz.getFields();
//3,遍歷數(shù)組,獲取每個(gè)Field
for (Field f : fs) {
//獲取變量名
System.out.println( f.getName() );
//獲取變量類型
System.out.println( f.getType().getName() );
}
}
//通過反射的技術(shù),獲取成員方法
private static void method3() {
//1,獲取Class對(duì)象
Class clazz = Student.class;
//2,獲取成員方法們
Method[] ms = clazz.getMethods();
//3,遍歷數(shù)組,獲取每個(gè)Method
for (Method m : ms) {
//獲取方法名
System.out.println(m.getName());
//獲取方法參數(shù)
Class<?>[] cs = m.getParameterTypes();
System.out.println( Arrays.toString(cs) );
}
}
//通過反射的技術(shù),獲取類中的構(gòu)造方法
private static void method2() {
//1,獲取Class對(duì)象
Class<Student> clazz = Student.class;
//2,獲取構(gòu)造方法們
Constructor<?>[] cs = clazz.getConstructors();
//3,foreach循環(huán)獲取每個(gè)構(gòu)造方法
for (Constructor<?> c : cs) {
//獲取構(gòu)造方法名
System.out.println(c.getName());
//獲取構(gòu)造方法的參數(shù)
Class<?>[] cs2 = c.getParameterTypes();
System.out.println(Arrays.toString(cs2));
}
}
//通過反射的技術(shù),獲取Class對(duì)象//三種方式
private static void method() throws ClassNotFoundException {
// -- static Class<?> forName(String className)--參數(shù)是類的全路徑
Class<?> clazz = Class.forName("java.lang.Object");
// -- 類名.class
Class<String> clazz2 = String.class;
// -- 對(duì)象.getClass()--泛型上限,最大是String類型,約束了元素的類型<=String類型
Class<? extends String> clazz3 = new String().getClass();
System.out.println("clazz = " + clazz);
System.out.println("clazz2 = " + clazz2);
System.out.println("clazz3 = " + clazz3);
}
}
暴力反射
暴力的獲取類中的私有資源順便獲取公開的,。
暴力反射和普通反射的反射原理是一樣的,,都是拿到.class文件中的所有數(shù)據(jù)并封裝成Class對(duì)象,通過各種方法來操作數(shù)據(jù),只不過是換了一套API
反射機(jī)制的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
反射提高了Java程序的靈活性和擴(kuò)展性,降低耦合性,,提高自適應(yīng)能力,。它允許程序創(chuàng)建和控制任何類的對(duì)象,無需提前硬編碼目標(biāo)類;反射是其它一些常用語言,,如C,、C++、Fortran 或者Pascal等都不具備的
缺點(diǎn):
-
性能問題:使用反射基本上是一種解釋操作,,用于字段和方法接入時(shí)要遠(yuǎn)慢于直接代碼,。因此Java反射機(jī)制主要應(yīng)用在對(duì)靈活性和擴(kuò)展性要求很高的系統(tǒng)框架上,普通程序不建議使用。
-
使用反射會(huì)模糊程序內(nèi)部邏輯:程序人員希望在源代碼中看到程序的邏輯,,反射等繞過了源代碼的技術(shù),,因而會(huì)帶來維護(hù)問題,。反射代碼比相應(yīng)的直接代碼更復(fù)雜,。
|