Java---注解、类加载器-加强-实现运行任意目录下class中加了@MyTest的空参方法

做自己的类加载器

虚拟机的核心是通过类加载器来加载.class文件,然后进行相应的解析执行。那么我们可以自己做类加载器,手动加载需要的.class以进行解析执行,从而扩展虚拟机的功能。

以下内容摘自API文档:

应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。

网络类加载器子类必须定义方法 findClass 和 loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass 来创建类实例。

代码示例:

自己的类加载器 MyClassLoader

package cn.hncu;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.junit.Test;

public class MyClassLoader extends ClassLoader{
    public Class<?> findClass(String name){
        //name = "e:\\cn\\hncu\\Person.class"
        Class c = null;
        FileInputStream in;
        byte[] b=null;

        //通过IO或网络把字节码数据读取到buf[]当中。进一步地,
        //如果我们自己熟悉字节码的生成格式,那么也可自己用程序生成。
        //本例,我们是把硬盘中的一个外部字节码文件的数据读取到buf[]当中
        //1
        try {
            in = new FileInputStream(name);
            byte[] buf = new byte[1024];
            ByteArrayOutputStream baos = new ByteArrayOutputStream();//字节流
            int len=0;
            while((len=in.read(buf))!=-1){
                baos.write(buf, 0, len);
            }
            in.close();
            baos.close();
            b = baos.toByteArray();
        //2 ---1-2这里可以抽取出来写一个loadClassData方法
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        c = defineClass("cn.hncu.Person", b, 0, b.length);
        return c;
    }

    @Test
    public void testClassData() throws ReflectiveOperationException{
        String className="cn.hncu.Person";
        //用Java的类加载器加载一个
        Class c = Class.forName(className);
        Object obj = c.newInstance();
        System.out.println(obj);
        System.out.println((Person)obj);

        System.out.println("-------------------");
        className = "e:\\cn\\hncu\\Person.class";
        Class c2 = findClass(className);
        Object obj2 = c2.newInstance();
        System.out.println(obj2);

        System.out.println((Person)obj2);//这句是有问题的
        //※不同类加载器加载的对象是无法强转---可以理解是不同的生存空间
        //Person p2 = (Person) obj2;//会挂的。
        //因为obj2的生存空间是MyClassLoader,而Person的生成空间是AppClassLoader
        //System.out.println(p2);

    }

}

测试结果:

看,最后那句不能输出吧。

因为不是一个类加载器的。

作自己的测试工具MyJUnit

(注解与反射共同使用的案例 )

相关说明:

1)JUnit用的是@Test注解,我们用@MyTest注解。

2)JUnit已经嵌入到MyEclipse当中,我们自己的MyJUnit只要能独立运行就可以(不嵌入),同时这样我们也不方便在MyJUnit中以参数方式接收到被测试类的类名与方法名,只能以键盘输入的方式接收。

3)JUnit能实现指定单个方法来调用执行,由于不能利用MyEclipse传参,因此我们在MyJUnit程序中遍历所有的方法并通过判断是否声明@MyTest注解来决定是否调用执行该方法。

下面实现了运行任意目录下的实现了@MyTest注解的方法:

需要输入绝对路径名和类的完整名字。

注解:@MyTest

package cn.hncu.myJunit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)//运行时也存在,必须要加这个
@Target (ElementType.METHOD)//限制注解只能加在方法上
public @interface MyTest {

}

测试类:TestPerson

package cn.hncu.myJunit;
/**
 * 测试用的
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-6
 */
public class TestPerson {

    public void run1(){
        System.out.println("run1...");
    }

    @MyTest
    public void run2(){
        System.out.println("run2...");
    }

    public void run3(){
        System.out.println("run3...");
    }

    @MyTest
    public void run4(){
        System.out.println("run4...");
    }

    public void run5(){
        System.out.println("run5...");
    }

}

MyClassLoader类:自己写的类加载器

package cn.hncu.myJunit;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 自己写的类加载器
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-6
 */
public class MyClassLoader extends ClassLoader{

//我把它分成2个方法写了。
    public  Class<?> findClass(String name, String className) {
        try {
            byte b[] = loadClassData(name);
            Class c = defineClass(className, b, 0, b.length);
            return c;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] loadClassData(String name) throws IOException {
        byte buf[] = new byte[1024];
        FileInputStream in = new FileInputStream(name);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int len=0;
        while((len=in.read(buf))!=-1){
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
        byte b[] = out.toByteArray();
        return b;
    }
}

main方法类:

package cn.hncu.myJunit;

import java.lang.reflect.Method;
import java.util.Scanner;

import cn.hncu.myJunit.MyClassLoader;

/**
 * @author 陈浩翔
 * @version 1.0  2016-5-6
 */
public class MyJunit {

    public static void main(String[] args) throws ReflectiveOperationException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入需要运行的类的绝对路径(路径中不能有空格,需要类的.class文件):");
        String name = sc.next();
        System.out.println("请输入类的名称(包含包名):");
        String className = sc.next();
        Class c = (new MyClassLoader()).findClass(name, className);
        //获得那个类了。

        //那个类必须要有空参构造方法
        Object obj = c.newInstance();

        //获得这个类所有声明的方法,包括私有的
        Method ms[] = c.getDeclaredMethods();
        for(Method m:ms){
            if(m.isAnnotationPresent(MyTest.class)){
                m.invoke(obj, null);
            }
        }
    }
}

运行测试结果:

现在我把class文件移动到D盘了。

再看运行结果:

这个可以有很多改进的地方,就比如每次输入路径都很麻烦,

我们可以做一个图形界面,让我们自己选择。

这样就方便多了。

时间: 2024-11-06 07:35:06

Java---注解、类加载器-加强-实现运行任意目录下class中加了@MyTest的空参方法的相关文章

Java---实现运行任意目录下class中加了@MyTest的空参方法(实现图形界面)

说明: 因为上个代码,总是要输入完整的绝对路径,比较麻烦,于是,就写了这个小程序,直接进入文件对话框选择需要运行的class文件. 只需要提前输入完整的类名. 注意:加的MyTest必须打个包,加上: import cn.hncu.myJuniitApp.vo.MyTest; 不然不是同一个注解呢. 测试的类: package cn.hncu.myJuniitApp; import cn.hncu.myJuniitApp.vo.MyTest; public class MyJunitTest {

java面向对象--类加载器及反射

类加载器 jvm 和 类的关系 当调用 java命令运行一个java程序时,会启动一个java虚拟机进程.同一个jvm的所有线程.所有变量都处于同一个进程里,都使用该jvm进程的内存区. jvm进程终止的情况: 1.程序运行到最后正常结束. 2.遇到System.exit()或Runtime.getRuntime.exit(). 3.遇到未捕获的异常或错误 4.程序所在的平台强制结束了JVM进程 jvm进程终止,jvm内存中的数据将全部丢失. 类加载 当程序主动使用某个类时,如果该类还未被加载到

深入java虚拟机-类加载器

此系列为深入java虚拟机(周志明著)学习笔记 通过一个类的全限定名来获取描述此类的二进制字节流的代码模块称为类加载器. 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性.通俗的理解:比较两个类是否"相等",只有在这两个类是同一类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载她们的类加载器不同,那这两个类必定不相等.这里的"相等",包括类的Class对象的equals()

java自定义类加载器

前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是eclipse项目中的bin目录里),然后通过java反射机制,获取main方法并执行..class文件名称固定.当 A.class文件更新的时候,问题出现了,main方法的执行结果总和第一次的执行结果相同. 程序流程 代码提交->接收代码->编译成A.class文件->java反射->m

分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码

先回顾一下classpath classpath的作用: classpath的作用是指定查找类的路径:当使用java命令执行一个类(类中的main方法)时,会从classpath中进行查找这个类. 指定classpath的方式一:         设置环境变量CLASSPATH,多个路径之间使用英文的分号隔开,也可以指定为jar包路径.          示例:CLASSPATH=c:/myclasses/;c/mylib/aa.jar;c:/mylib/bb.jar;.          注意

Java的类加载器种类

Java类加载器采用双亲委派模型: 1.启动类加载器:这个类加载器负责放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库.用户无法直接使用. 2.扩展类加载器:这个类加载器由sun.misc.Launcher$AppClassLoader实现.它负责<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库.用户可以直接使用. 3.应用程序类加载器:这个类

java 用类加载器的方式管理资源和配置文件

public class ReflectTest {public static void main(String[] args) throws Exception {    //config.properties 与当前类在不同包下:    InputStream is=ReflectTest.class.getResourceAsStream("/com/jhon/copy/config.properties");    //在同一个包下    //InputStream is=Re

Java的类加载器

1. Java的类加载器的种类都有哪些? 1.根类加载器(Bootstrap) --C++写的 ,看不到源码 2.扩展类加载器(Extension) --加载位置 :jre\lib\ext中 3.系统(应用)类加载器(System\App) --加载位置 :classpath中 4.自定义加载器(必须继承ClassLoader) 2. 类什么时候被初始化?  1)创建类的实例,也就是new一个对象 2)访问某个类或接口的静态变量,或者对该静态变量赋值 3)调用类的静态方法 4)反射(Class.

如何配置任意目录下Web应用程序

1,首先创建一个Web项目,tomcat 7, JDK 1.8 2,创建Web项目并部署到tomcat服务器下运行的步骤和方法: 在Eclipse下创建一个JAVA project 在JAVA项目下创建Web开发的目录结构 -WEB-INF -classes(编译后的class文件必须放在该目录下,如何修改Eclipse项目的class文件输出目录请参考:http://www.cnblogs.com/revel171226/p/8690792.html) -lib(这个目录主要是房web项目需要