一反射機制的概念:指在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法,對于任意一個對象,都能調用它的任意一個方法.這種動態(tài)獲取信息,以及動態(tài)調用對象方法的功能叫java語言的反射機制.java反射機制是圍繞Class類展開的,在深入java反射原理之前,需要對類加載機制有一個大致的了解。jvm使用ClassLoader將字節(jié)碼文件(class文件)加載到方法區(qū)內存中:Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.mypackage.MyClass");可見ClassLoader根據類的完全限定名加載類并返回了一個Class對象,而java反射的所有起源都是從這個class類開始的??磦€列子://1.獲取類
?Class c = Class.forName("_12_CustomerService");
//獲取某個特定的方法
//通過:方法名+形參列表
?Method m = c.getDeclaredMethod("login",String.class,String.class);
//通過反射機制執(zhí)行l(wèi)ogin方法.
Object o = c.newInstance();
//調用o對象的m方法,傳遞"admin""123"參數,方法的執(zhí)行結果是retValue
Object retValue = m.invoke(o, "admin","123");
System.out.println(retValue); //true
二.反射機制的作用
1.在運行時判斷任意一個對象所屬的類;
2.在運行時獲取類的對象;
3.在運行時訪問java對象的屬性,方法,構造方法等。
三.反射機制的優(yōu)點與缺點
首先要搞清楚為什么要用反射機制?直接創(chuàng)建對象不就可以了嗎,這就涉及到了動態(tài)與靜態(tài)的概念。靜態(tài)編譯:在編譯時確定類型,綁定對象,即通過。動態(tài)編譯:運行時確定類型,綁定對象。動態(tài)編譯最大限度發(fā)揮了java的靈活性,體現(xiàn)了多態(tài)的應用,有以降低類之間的藕合性。?
反射機制的優(yōu)點:可以實現(xiàn)動態(tài)創(chuàng)建對象和編譯,體現(xiàn)出很大的靈活性(特別是在J2EE的開發(fā)中它的靈活性就表現(xiàn)的十分明顯)。通過反射機制我們可以獲得類的各種內容,進行了反編譯。對于JAVA這種先編譯再運行的語言來說,反射機制可以使代碼更加靈活,更加容易實現(xiàn)面向對象
反射機制的缺點:對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它 滿足我們的要求。這類操作總是慢于只直接執(zhí)行相同的操作。
1.通過一個對象獲得完整的包名和類名
添加一句:所有類的對象其實都是Class的實例。
class?Demo{?//other codes...??}?class?hello{public?static?void?main(String[] args) {Demo demo=new?Demo(); ??????System.out.println(demo.getClass().getName());}}
2.實例化Class類對象
public static void main(String[] args) {
Class<?> demo1=null;
Class<?> demo2=null;
Class<?> demo3=null;
try{
//一般盡量采用這種形式
?demo1=Class.forName("Reflect.Demo");
}catch(Exception e){
e.printStackTrace();
}
emo2=new Demo().getClass();
demo3=Demo.class;
System.out.println("類名稱 ??"+demo1.getName());
System.out.println("類名稱 ??"+demo2.getName());
System.out.println("類名稱 ??"+demo3.getName());
【運行結果】:
類名稱Reflect.Demo
類名稱Reflect.Demo
類名稱Reflect.Demo
3.通過Class實例化其他類的對象
class Person{
??????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 "["+this.name+" ?"+this.age+"]";
?????}
?????private String name;
?????private int age;
?}
?class hello{
?????public static void main(String[] args) {
?????????Class<?> demo=null;
?????????try{
????????????demo=Class.forName("Reflect.Person");
?????????}catch (Exception e) {
?????????????e.printStackTrace();
?????????}
?????????Person per=null;
?????????try {
????????????per=(Person)demo.newInstance();
?????????} catch (InstantiationException e) {
?????????????// TODO Auto-generated catch block
?????????????e.printStackTrace();
?????????} catch (IllegalAccessException e) {
?????????????// TODO Auto-generated catch block
?????????????e.printStackTrace();
?????????}
?????????per.setName("Rollen");
?????????per.setAge(20);
?????????System.out.println(per);
?????}
?}
4.通過Class調用其他類中的構造函數 (也可以通過這種方式通過Class創(chuàng)建其他類的對象)
package Reflect;
import java.lang.reflect.Constructor;
class Person{
????public Person() {
????}
????public Person(String name){
????????this.name=name;
????}
????public Person(int age){
????????this.age=age;
????}
????public Person(String name, int age) {
????????this.age=age;
????????this.name=name;
????}
????public String getName() {
????????return name;
????}
????public int getAge() {
????????return age;
????}
????@Override
????public String toString(){
????????return "["+this.name+" ?"+this.age+"]";
????}
????private String name;
????private int age;
}
class hello{
????public static void main(String[] args) {
????????Class<?> demo=null;
????????try{
????????????demo=Class.forName("Reflect.Person");
????????}catch (Exception e) {
????????????e.printStackTrace();
????????}
????????Person per1=null;
????????Person per2=null;
????????Person per3=null;
????????Person per4=null;
//取得全部的構造函數
????????Constructor<?> cons[]=demo.getConstructors();
????????try{
????????????per1=(Person)cons[0].newInstance();
????????????per2=(Person)cons[1].newInstance("Rollen");
????????????per3=(Person)cons[2].newInstance(20);
????????????per4=(Person)cons[3].newInstance("Rollen",20);
????????}catch(Exception e){
????????????e.printStackTrace();
????????}
????????System.out.println(per1);
????????System.out.println(per2);
????????System.out.println(per3);
????????System.out.println(per4);
????}
}
5.取得其他類中的父類
class hello{
????public static void main(String[] args) {
????????Class<?> demo=null;
????????try{
????????????demo=Class.forName("Reflect.Person");
????????}catch (Exception e) {
????????????e.printStackTrace();
????????}
//取得父類
????????Class<?> temp=demo.getSuperclass();
System.out.println("繼承的父類為: ??"+temp.getName());
????}
}
//【運行結果】
//繼承的父類為: ??java.lang.Object
6.通過反射操作屬性
class hello {
????public static void main(String[] args) throws Exception {
????????Class<?> demo = null;
????????Object obj = null;
????????demo = Class.forName("Reflect.Person");
????????obj = demo.newInstance();
????????Field field = demo.getDeclaredField("sex");
????????field.setAccessible(true);
field.set(obj, "男");
????????System.out.println(field.get(obj));
}
7.通過反射調用其他類中的方法
class hello {
????public static void main(String[] args) {
????????Class<?> demo = null;
????????try {
????????????demo = Class.forName("Reflect.Person");
????????} catch (Exception e) {
????????????e.printStackTrace();
????????}
????????try{
//調用Person類中的sayChina方法
????????????Method method=demo.getMethod("sayChina");
????????????method.invoke(demo.newInstance());
//調用Person的sayHello方法
????????????method=demo.getMethod("sayHello", String.class,int.class);
????????????method.invoke(demo.newInstance(),"Rollen",20);
????????}catch (Exception e) {
????????????e.printStackTrace();
????????}
????}
}
//【運行結果】:
//hello ,china
//Rollen ?20
用幾句話總結反射的實現(xiàn)原理:
1.反射類及反射方法的獲取,都是通過從列表中搜尋查找匹配的方法,所以查找性能會隨類的大小方法多少而變化;
2.每個類都會有一個與之對應的Class實例,從而每個類都可以獲取method反射方法,并作用到其他實例身上;
3.反射也是考慮了線程安全的,放心使用;
4.反射使用軟引用relectionData緩存class信息,避免每次重新從jvm獲取帶來的開銷;
5.反射調用多次生成新代理Accessor, 而通過字節(jié)碼生存的則考慮了卸載功能,所以會使用獨立的類加載器;
6.當找到需要的方法,都會copy一份出來,而不是使用原來的實例,從而保證數據隔離;
7.調度反射方法,最終是由jvm執(zhí)行invoke0()執(zhí)行;