1. 簡介反射是Java被視爲動態(或準動態)語言的一個關鍵性質。這個機制容許程序在運行時透過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifiers(諸如public, static 等)、superclass(例如Object)、實現之interfaces(例如Cloneable),也包括fields和methods的全部信息,並可於運行時改變fields內容或喚起methods; 反射機制允許程序在運行時加載、探知、使用編譯期間徹底未知的classes。經過JAVA的反射機制,能夠得到程序內部或第三方JAR包的CLASS,METHOD,屬性,參數等信息。html
2.JAVA動態加載類和靜態加載類的區別java
它們倆本質的區別在於靜態加載的類的源程序在編譯時期加載(必須存在),而動態加載的類在編譯時期能夠缺席(源程序沒必要存在)。ide
3. JAVA動態加載類和靜態加載類的方式this
1 ).程序在編譯時執行,在執行過程當中加載全部可能執行到的程序。在這種加載方式下,只要加載中一個方法出錯,程序就不能運行。咱們通常寫程序默認的是靜態加載;new建立對象的方式稱做爲靜態加載。.net
2).動態加載(類惟一字節碼對象); 程序在運行時調用相應方法,即便其餘方法是錯誤的,程序依舊會執行。經過動態加載可讓程序的可延長性大大提高,對之後的維護和擴展有重要意義。線程
Class c1=Class.forName("XXX");代理
Class c2= XXX.class; excel
XXX u1=new XXX(); Class c3=u1.getClass(); htm
使用當前類的ClassLoader 對象
ClassLoader clo1 =this.getClass.getClassLoader();
Class c3=clo1.loadClass("XXX");
使用當前線程的ClassLoader
ClassLoader clo2 =Thread.currentThread().getContextClassLoader();
Class c4=clo2.loadClass("XXX");
使 用系統ClassLoader,即系統的入口點所使用的ClassLoader,(注意,system ClassLoader與根 ClassLoader並不同。JVM下system ClassLoader一般爲App ClassLoader)
ClassLoader clo3=ClassLoader.getSystemClassLoader();
Class c5=clo3.loadClass("XXX");
4.舉兩個實際例子說明:
1)例一
public interface IUser {
}
package reflect;
public class User implements IUser{
private String name;
private int id;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
}
public static void main (String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
Class c1=Class.forName("reflect.User");//每一個類對應一個字節碼實體對象
Class c2=User.class; //每一個類對應一個字節碼實體對象
User u1=new User();//構造器實例化一個對象
Class c3=u1.getClass();//該對象對應的字節碼實體對象
Object o1=c1.newInstance();//該類反射出的實例
Object o2=c2.newInstance();//該類反射出的實例
System.out.print(o1==o2);//false
System.out.print(c3==c1);//true
System.out.print(c1==c2);//true
ClassLoader clo=Thread.currentThread().getContextClassLoader();
ClassLoader clos=ClassLoader.getSystemClassLoader();
Class c4=clo.loadClass("reflect.User");
Class c5=clo.loadClass("reflect.User");
System.out.println(c5==c1);//true
System.out.print(c4==c1);//true
//利用反射獲取一個類的屬性
Field[] fs = c1.getDeclaredFields();
for(Field field:fs){
System.out.println("得到屬性的修飾符,例如public,static等等 >>"+Modifier.toString(field.getModifiers()));
System.out.println("屬性的類型的名字 >>"+field.getType());
System.out.println("屬性的名字 >>"+field.getName());
}
Method[] ms = c1.getDeclaredMethods();
for(Method field:ms){
System.out.println("得到方法的修飾符,例如public,static等等 >>"+Modifier.toString(field.getModifiers()));
System.out.println("方法的參數個數 >>"+field.getParameterTypes().length);
System.out.println("方法的名字 >>"+field.getName());
}
System.out.println("c1的父類>>"+c1.getSuperclass()); //c1的父類>>class java.lang.Object
Class[] cs=c1.getInterfaces();
for(Class field:cs){
System.out.println("接口的名字 >>"+field.getName()); //接口的名字 >>reflect.IUser
}
Method method=c1.getDeclaredMethod("setName", String.class);
method.invoke(o1, "guolzlijing");
Method method2=c1.getDeclaredMethod("getName", null);
System.out.println(method2.invoke(o1, null));//guolzlijing
}
2)解釋關鍵字:
方法關鍵字
getDeclaredMethods()
獲取全部的方法(不包括繼承類)
getDeclaredMethod方法第一個參數指定一個須要調用的方法名稱
第二個參數是須要調用方法的參數類型列表,是參數類型!如無參數能夠指定null。
參數必須和方法中同樣int和Integer,double和Double被視爲不一樣的類型。
反射中getMethods 與 getDeclaredMethods 的區別
public Method[] getMethods()返回某個類的全部公用(public)方法包括其繼承類的公用方法,固然也包括它所實現接口的方法。
public Method[] getDeclaredMethods()對象表示的類或接口聲明的全部方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。
固然也包括它所實現接口的方法。
getReturnType()
得到方法的反回類型
getParameterTypes()
得到方法的傳入參數類型
getDeclaredMethod("方法名",參數類型.class,……)
得到特定的方法
構造方法關鍵字
getDeclaredConstructors()
獲取全部的構造方法(不包括繼承類)
getDeclaredConstructor(參數類型.class,……)
獲取特定的構造方法
父類和父接口
getSuperclass()
獲取某類的父類
getInterfaces()
獲取某類實現的接口
Invoke
一個方法能夠生成多個Method對象,但只有一個root對象,主要用於持有一個MethodAccessor對象,這個對象也能夠認爲一個方法只有一個,至關因而static的,由於Method的invoke是交給MethodAccessor執行的。
能夠看到Method.invoke()實際上並非本身實現的反射調用邏輯,而是委託給sun.reflect.MethodAccessor來處理。
每一個實際的Java方法只有一個對應的Method對象做爲root。這個root是不會暴露給用戶的,而是每次在經過反射獲取Method對象時新建立Method對象把root包裝起來再給用戶。
在第一次調用一個實際Java方法對應得Method對象的invoke()方法以前,實現調用邏輯的MethodAccessor對象還沒建立;
等第一次調用時才新建立MethodAccessor並更新給root,而後調用MethodAccessor.invoke()真正完成反射調用。
AVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
Java反射機制主要提供瞭如下功能: 在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具備的成員變量和方法;在運行時調用任意一個對象的方法;生成動態代理。
3)例子二:
public interface RunBetter {
public void startPro();
}
public class Word implements RunBetter{
public void startPro() {
// TODO Auto-generated method stub
System.out.println("Word Test!");
}
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//靜態加載。編譯時加載,編譯時就須要加載所有可能使用到的的類,一個類出錯,其餘類的功能都不能獲得執行 以下注釋將編譯不經過
/*if("Word".equals(args[0])){
Word Word = new Word();
System.out.println("Word");
}
if("Excel".equals(args[0])){
Excel excel = new Excel();
System.out.println("Excel");
}
}*/
Class c1 = Class.forName(GetProperties.use_classLoador());//配置文件中讀取具體實現類
//在這個代碼中咱們經過得到類類型newInstance。而後再執行startPro中的方法。
//爲何不將RunBetter rb = (RunBetter)c1.newInstance();寫成 MainLoad rb = (MainLoad)c1.newInstance(); ???
//不利於拓展,若是有多個實現類都執行startPro方法,這樣每加一個類都須要改動源代碼程序;接口的形式,只須要 關注接口不關注具體實現類是哪個;也是多態性
RunBetter rb = (RunBetter)c1.newInstance();
rb.startPro();
}
4)例子三:
public interface Attribute {
abstract void belongNature();
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Scanner sc=new Scanner(System.in);
System.out.println("請輸入人羣,獲取屬性……");
while(true){
String action=sc.nextLine();
if("exit".equals(action)){
return;
}
if(action.length()>0){
runClassLoader(action);
}
}
}
static void run(String action){
switch (action) {
case "Student":
Student student=new Student();
student.belongNature();
break;
case "Teacher":
Teacher teacher=new Teacher();
teacher.belongNature();
break;
default:
break;
}
}
static void runClassLoader(String action) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
switch (action) {
case "Student":
Class class1=Class.forName(GetProperties.use_classLoador("class_student"));
Attribute attribute=(Attribute)class1.newInstance();
attribute.belongNature();
break;
case "Teacher":
Class class2=Class.forName(GetProperties.use_classLoador("class_teacher"));
Teacher attribute2=(Teacher)class2.newInstance();
attribute2.belongNature();
break;
default:
break;
}
}