1. 程式人生 > >Java動態載入一個類的幾種方法以及invoke

Java動態載入一個類的幾種方法以及invoke

一.載入一個類的幾種方法

介面

IUser

package org.me.javaapp;

/**
 *
 * @author Administrator
 */
public interface IUser {
    
}

User.java
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.me.javaapp;

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{  
    try{
            Class c1=Class.forName("org.me.javaapp.User");
            Class c2=User.class;
            Object o1=c1.newInstance();
            Object o2=c2.newInstance();
            User u1=new User();
            Class c3=u1.getClass();
            
            /*
            this.getClass.getClassLoader();
            // 使用當前類的ClassLoader  
            
            Thread.currentThread().getContextClassLoader();            
            // 使用當前執行緒的ClassLoader  
            
            ClassLoader.getSystemClassLoader(); 
            // 使 用系統ClassLoader,即系統的入口點所使用的ClassLoader。(注意,system ClassLoader與根 ClassLoader並不一樣。JVM下system ClassLoader通常為App ClassLoader)  
            */
            ClassLoader clo=Thread.currentThread().getContextClassLoader();
            Class c4=clo.loadClass("org.me.javaapp.User");
            
            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.getParameterCount());
                System.out.println("方法的名字 >>"+field.getName());
            }
            System.out.println("c1的父類>>"+c1.getSuperclass());

            Class[] cs=c1.getInterfaces();
            for(Class field:cs){  
                System.out.println("介面的名字 >>"+field.getName());
            }
            System.out.println(">>>>>>>>>>>");
        }
        catch (Exception ex){
        System.out.println(ex.toString());
        }
    }

輸出:

獲得屬性的修飾符,例如public,static等等 >>private
屬性的型別的名字 >>class java.lang.String
屬性的名字 >>name
獲得屬性的修飾符,例如public,static等等 >>private
屬性的型別的名字 >>int
屬性的名字 >>id
獲得方法的修飾符,例如public,static等等 >>public
方法的引數個數 >>0
方法的名字 >>getName
獲得方法的修飾符,例如public,static等等 >>public
方法的引數個數 >>0
方法的名字 >>getId
獲得方法的修飾符,例如public,static等等 >>public
方法的引數個數 >>1
方法的名字 >>setName
獲得方法的修飾符,例如public,static等等 >>public
方法的引數個數 >>1
方法的名字 >>setId
c1的父類>>class java.lang.Object
介面的名字 >>org.me.javaapp.IUser


獲取方法,和構造方法,不再詳細描述,只來看一下關鍵字:
方法關鍵字
含義
getDeclaredMethods()
獲取所有的方法
getReturnType()
獲得方法的放回型別
getParameterTypes()
獲得方法的傳入引數型別
getDeclaredMethod("方法名",引數型別.class,……)
獲得特定的方法
 
 
構造方法關鍵字
含義
getDeclaredConstructors()
獲取所有的構造方法
getDeclaredConstructor(引數型別.class,……)
獲取特定的構造方法
 
 
父類和父介面
含義
getSuperclass()
獲取某類的父類
getInterfaces()
獲取某類實現的介面

ClassLoader主要對類的請求提供服務,當JVM需要某類時,它根據名稱向ClassLoader要求這個類,然後由ClassLoader返回這個類的class物件。

二.Invoke

一個方法可以生成多個Method物件,但只有一個root物件,主要用於持有一個MethodAccessor物件,這個物件也可以認為一個方法只有一個,相當於是static的,因為Method的invoke是交給MethodAccessor執行的。

package org.me.javaapp;

public class Child extends Person{
    
    public void say(String s) {
        System.out.println("Hello invork>>>"+s);
    }
    
    public void add(int a,int b) {
        a+=b;
        System.out.println("a+b="+a);
    }
}

invoke呼叫
package org.me.test;

import java.lang.reflect.Method;
import org.junit.Test;

public class TestInvoke {

    @Test
    public void testSingleton() throws Exception {
        Class<?> clz = Class.forName("org.me.javaapp.Child");
        Object o = clz.newInstance();
        Method m = clz.getMethod("add", int.class,int.class);
        m.invoke(o, 1,2);
        m = clz.getDeclaredMethod("say", String.class);
        m.invoke(o,"http://blog.csdn.net/unix21/");
    }
}


參考:

getMethod方法第一個引數指定一個需要呼叫的方法名稱
第二個引數是需要呼叫方法的引數型別列表,是引數型別!如無引數可以指定null。
引數必須和方法中一樣int和Integer,double和Double被視為不同的型別。

public Method[] getMethods()返回某個類的所有公用(public)方法包括其繼承類的公用方法,當然也包括它所實現介面的方法。
public Method[] getDeclaredMethods()物件表示的類或介面宣告的所有方法,包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法

當然也包括它所實現介面的方法。

可以看到Method.invoke()實際上並不是自己實現的反射呼叫邏輯,而是委託給sun.reflect.MethodAccessor來處理。 
每個實際的Java方法只有一個對應的Method物件作為root。這個root是不會暴露給使用者的,而是每次在通過反射獲取Method物件時新建立Method物件把root包裝起來再給使用者。
在第一次呼叫一個實際Java方法對應得Method物件的invoke()方法之前,實現呼叫邏輯的MethodAccessor物件還沒建立;
等第一次呼叫時才新建立MethodAccessor並更新給root,然後呼叫MethodAccessor.invoke()真正完成反射呼叫。

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
Java反射機制主要提供了以下功能: 在執行時判斷任意一個物件所屬的類;在執行時構造任意一個類的物件;在執行時判斷任意一個類所具有的成員變數和方法;在執行時呼叫任意一個物件的方法;生成動態代理。

三.Class<?>與Class

Class<?> clz = Class.forName("org.me.javaapp.Child");
        Class clzz = Class.forName("org.me.javaapp.Child");
        Object o = clzz.newInstance();
        Method m = clz.getMethod("add", int.class,int.class);
        m.invoke(o, 1,2);
        m = clz.getDeclaredMethod("say", String.class);
        m.invoke(o,"http://blog.csdn.net/unix21/");
效果是一樣的。