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盘了。
再看运行结果:
这个可以有很多改进的地方,就比如每次输入路径都很麻烦,
我们可以做一个图形界面,让我们自己选择。
这样就方便多了。
Java---注解、类加载器-加强-实现运行任意目录下class中加了@MyTest的空参方法的更多相关文章
- Java---实现运行任意目录下class中加了@MyTest的空参方法(实现图形界面)
说明: 因为上个代码,总是要输入完整的绝对路径,比较麻烦,于是,就写了这个小程序,直接进入文件对话框选择需要运行的class文件. 只需要提前输入完整的类名. 注意:加的MyTest必须打个包,加上: ...
- Java虚拟机类加载器及双亲委派机制
所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...
- Java 虚拟机类加载器
虚拟机设计团队把类加载阶段张的”通过一个类的全限定名来获取此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为”类加载器”. ...
- java面向对象--类加载器及Class对象
类加载器 jvm 和 类的关系 当调用 java命令运行一个java程序时,会启动一个java虚拟机进程.同一个jvm的所有线程.所有变量都处于同一个进程里,都使用该jvm进程的内存区. jvm进程终 ...
- java ClassLoader类加载器
原文 首先来了解一下字节码和class文件的区别: 我们知道,新建一个java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java ...
- Java之类加载器(Class Loader)
JVM默认有三个类加载器: Bootstrap Loader Bootstrap Loader通常有C编写,贴近底层操作系统.是JVM启动后,第一个创建的类加载器. Extended Loader E ...
- 深入探讨java的类加载器
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Ja ...
- java自定义类加载器
前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...
- Java的类加载器
一.类加载器的概念 类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 ...
随机推荐
- 未能加载文件或程序集“Newtonsoft.Json, Version=4.5.0.0[已解决]
在使用百度UEditor,不小心将Newtonsoft.Json,升级了,然后就报的一个错,说: 其他信息: 未能加载文件或程序集“Newtonsoft.Json, Version=4.5.0.0, ...
- Nuget 相关
1:服务器搭建 1.1:创建空的Web Application 1.2:引用NuGet.Server 包:NuGet.Server 安装完成后的界面 web.config 已经被重写了,里面存在一些配 ...
- Android四大组件之一:ContentProvider(内容提供者)
Android中还提供了名为ContentProvider(内容提供者),可以向其他应用提供数据,但不常用,除非是同一公司开发的App,可以向不同应用提供数据.虽然为Android的四大组件之一,但用 ...
- 在企业级开发中使用Try...Catch...会影响效率吗?
感谢神啊.上帝及老天爷让我失眠,才能够有了本篇文章. 记得不久之前,公司一同事曾经说过:“如果是Winform开发,由于程序是在本地,使用try...catch不会有太大性能问题,可是如果是在web服 ...
- MySQL性能测试工具之mysqlslap使用详解
mysqlslap是mysql自带的基准测试工具,优点:查询数据,语法简单,灵活容易使用.该工具可以模拟多个客户端同时并发的向服务器发出查询更新,给出了性能测试数据而且提供了多种引擎的性能比较.msq ...
- Oracle AWR报告指标全解析-11011552
1-5 Top 5 Timed EventsWaits : 该等待事件发生的次数, 对于DB CPU此项不可用Times : 该等待事件消耗的总计时间,单位为秒, 对于DB CPU 而言是前台进程所消 ...
- linux下启动oracle服务命令
以redflag(redhat /centos)linux下的 oracle 10g 为例: 如果oracle安装和配置都没有问题的话: 依次执行以下代码即可启动oracle服务. #su - ora ...
- iOS 获取通讯录里边的电话号码AddressBook
1 首先导入库 <AddressBook/AddressBook.h> 2 然后在导入#import <AddressBook/AddressBook.h>文件 3 声明 ...
- Visual Studio2010 安装msdn
1.注册VS2010 断网(不要冒险)->运行Microsoft Visual Studio 2010->帮助->注册产品->YCFHQ-9DWCY-DKV88-T2TMH-G ...
- SGU 125.Shtirlits
时间限制:0.25s 空间限制:4M 题意: 有N*N的矩阵(n<=3),对所有i,j<=n有G[i][j]<=9,定义f[i][j]为G[i][j]四周大于它的数的个数(F[i][ ...