java動態與靜態加載類(二)

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{

@Override

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;

         }

     }

相關文章
相關標籤/搜索