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/");
效果是一樣的。