Java动态加载一个类的几种方法以及invoke

时间:2020-12-23 19:24:38

一.加载一个类的几种方法

接口

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());
        }
    }

Java动态加载一个类的几种方法以及invoke

输出:

获得属性的修饰符,例如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

参考:JAVA中的反射机制

获取方法,和构造方法,不再详细描述,只来看一下关键字:
方法关键字
含义
getDeclaredMethods()
获取所有的方法
getReturnType()
获得方法的放回类型
getParameterTypes()
获得方法的传入参数类型
getDeclaredMethod("方法名",参数类型.class,……)
获得特定的方法
 
 
构造方法关键字
含义
getDeclaredConstructors()
获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)
获取特定的构造方法
 
 
父类和父接口
含义
getSuperclass()
获取某类的父类
getInterfaces()
获取某类实现的接口


ClassLoader 详解及用途

ClassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回这个类的class对象。


java中的反射总结 【举例不错,很全面】


二.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/");
    }
}
Java动态加载一个类的几种方法以及invoke

参考:

java中的反射,invoke方法

getMethod方法第一个参数指定一个需要调用的方法名称
第二个参数是需要调用方法的参数类型列表,是参数类型!如无参数可以指定null。
参数必须和方法中一样int和Integer,double和Double被视为不同的类型。


反射中getMethods 与 getDeclaredMethods 的区别

public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法

当然也包括它所实现接口的方法。


JAVA深入研究——Method的Invoke方法【非常深入,讲了实现细节】

可以看到Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。 
每个实际的Java方法只有一个对应的Method对象作为root。这个root是不会暴露给用户的,而是每次在通过反射获取Method对象时新创建Method对象把root包装起来再给用户。
在第一次调用一个实际Java方法对应得Method对象的invoke()方法之前,实现调用逻辑的MethodAccessor对象还没创建;
等第一次调用时才新创建MethodAccessor并更新给root,然后调用MethodAccessor.invoke()真正完成反射调用。

java反射机制详解 及 Method.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/");
效果是一样的。