java动态编译类文件并加载到内存中

  如果你想在动态编译并加载了class后,能够用hibernate的数据访问接口以面向对象的方式来操作该class类,请参考笔者的这篇博文-(该博文暂未发布)

  所谓动态编译,就是在程序运行时产生java类,并编译成class文件。  

  一、这里介绍两种动态编译java文件的方式。

    第一种:使用Runtime执行javac命令

/**
     * 编译java类
     * 使用Runtime执行javac命令
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static void javac(String name) throws IOException {
        String javaPackageName = name.replace(".",File.separator)+".java";
        String javaAbsolutePath = classPath+javaPackageName;
        Process process = Runtime.getRuntime().exec("javac -classpath "+ jarAbsolutePath+ " " + javaAbsolutePath);
        try {
            InputStream errorStream = process.getErrorStream();
            InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String line = null;
            while ((line=bufferedReader.readLine()) != null){
                System.out.println(line);
            }
            int exitVal = process.waitFor();
            System.out.println("Process exitValue: " + exitVal);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    第二种:使用jdk自带的rt.jar中的javax.tools包提供的编译器

/**
     * 编译java类
     * 使用rt.jar中的javax.tools包提供的编译器
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static void compiler(String name) throws IOException {
        String javaPackageName = name.replace(".",File.separator)+".java";
        String javaAbsolutePath = classPath+javaPackageName;
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        compiler.run(null,null,null,"-encoding","UTF-8","-classpath",jarAbsolutePath.toString(),javaAbsolutePath);
    }

  二、使用Class.forName("");将class文件加载到内存中,并得到该类的class对象

/**
     * 动态编译一个java源文件并加载编译生成的class
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static Class<?> dynamicLoadClass(String name) throws IOException, ClassNotFoundException {
        if (!isClassExist(name)){
            compiler(name);
        }
        if(isJavaExist(name)){
            if(!FileUtil.destroyFile(classPath + name.replace(".",File.separator)+".java")){
                System.out.println("========================================>>>>删除源文件失败!");
            }
        }
        return Class.forName(name);
    }

  以下是全部代码:

package com.basic.core.classloader;

import com.basic.core.util.FileUtil;
import sun.tools.jar.Main;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * desc:自定义的类加载器,用于实现类的动态加载
 */
public class MyClassLoader extends ClassLoader {

    //类路径
    private static String classPath ;

    private static String jarPrefix;

    private static StringBuilder jarAbsolutePath;

    static{
        classPath = MyClassLoader.class.getClassLoader().getResource("").getPath();
        classPath = !classPath.startsWith("/")?classPath:classPath.substring(1);//去掉开始位置的/
        classPath = classPath.endsWith(File.separator)?classPath:classPath+File.separator;
        jarPrefix = classPath.substring(0,classPath.lastIndexOf("classes"))+File.separator+"lib"+File.separator;
        jarAbsolutePath = new StringBuilder().append(jarPrefix)
                .append("hibernate-core-4.2.0.Final.jar;")
                .append(jarPrefix).append("hibernate-jpa-2.0-api-1.0.1.Final.jar;")
                .append(jarPrefix).append("validation-api-1.0.0.GA.jar;");
    }

    /**
     * 如果父的类加载器中都找不到name指定的类,
     * 就会调用这个方法去从磁盘上加载一个类
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @return
     * @throws java.io.IOException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = null;
        Class<?> clazz = null;
        try {
            //加载类的字节码
            classBytes = loadClassBytes(name);
            //将字节码交给JVM
            clazz = defineClass(name,classBytes,0,classBytes.length);
            if(clazz == null){
                throw new ClassNotFoundException(name);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return clazz;
    }

    /**
     * 加载类的字节码
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @return
     * @throws java.io.IOException
     */
    private byte[] loadClassBytes(String name) throws IOException {
        String classPackageName = name.replace(".",File.separator)+".class";
        String classAbsolutePath = classPath+classPackageName;
        //编译java文件
        javac(name);
        byte[] bytes = Files.readAllBytes(Paths.get(classAbsolutePath));
        return bytes;
    }

    /**
     * 指定的类的class是否存在
     * @param name
     * @return
     * @throws IOException
     */
    public static boolean isClassExist(String name) throws IOException {
        String classPackageName = name.replace(".",File.separator)+".class";
        return FileUtil.isExists(classPath+classPackageName)?true:false;
    }

    /**
     * 指定的类是否存在
     * @param name
     * @return
     * @throws IOException
     */
    public static boolean isJavaExist(String name) throws IOException {
        String classPackageName = name.replace(".",File.separator)+".java";
        return FileUtil.isExists(classPath+classPackageName)?true:false;
    }

    /**
     * 编译java类
     * 使用Runtime执行javac命令
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static void javac(String name) throws IOException {
        String javaPackageName = name.replace(".",File.separator)+".java";
        String javaAbsolutePath = classPath+javaPackageName;
        Process process = Runtime.getRuntime().exec("javac -classpath "+ jarAbsolutePath+ " " + javaAbsolutePath);
        try {
            InputStream errorStream = process.getErrorStream();
            InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String line = null;
            while ((line=bufferedReader.readLine()) != null){
                System.out.println(line);
            }
            int exitVal = process.waitFor();
            System.out.println("Process exitValue: " + exitVal);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 编译java类
     * 使用rt.jar中的javax.tools包提供的编译器
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static void compiler(String name) throws IOException {
        String javaPackageName = name.replace(".",File.separator)+".java";
        String javaAbsolutePath = classPath+javaPackageName;
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        compiler.run(null,null,null,"-encoding","UTF-8","-classpath",jarAbsolutePath.toString(),javaAbsolutePath);
    }

    /**
     * 动态编译一个java源文件并加载编译生成的class
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static Class<?> dynamicLoadClass(String name) throws IOException, ClassNotFoundException {
        if (!isClassExist(name)){
            compiler(name);
        }
        if(isJavaExist(name)){
            if(!FileUtil.destroyFile(classPath + name.replace(".",File.separator)+".java")){
                System.out.println("========================================>>>>删除源文件失败!");
            }
        }
        return Class.forName(name);
    }

    public static void main (String[] args){

    }

}

  

 

时间: 2024-10-13 22:51:26

java动态编译类文件并加载到内存中的相关文章

linux函数深入探索——open函数打开文件是否将文件内容加载到内存空间

转自:https://blog.csdn.net/qq_17019203/article/details/85051627 问题:open(2)函数打开文件是否将文件内容加载到内存空间 首先,文件打开后都会产生一个文件描述符fd,这个文件描述符其实是记录在PCB的文件描述符表中,而这个文件描述符实质上是一个结构体,用来存放跟打开文件相关的信息,基于此前提,我产生了两种假设 1.文件描述符结构体中只存储了文件在硬盘中的相应地址信息,并不将文件内容加载到内存中,这样做的好处是减少内存空间的占用,但大

PHP的 Final关键字、类(文件)的加载和命名空间

** Final.类(文件)的加载和命名空间 1.final 关键字-----终态的.最终的 final 关键字用于修饰类和方法:修饰的类不能被继承,修饰的函数方法(public)在子类中不能被重载. 如果父类中的方法被声明为 final,则子类无法覆盖该方法.如果一个类被声明为 final,则不能被继承. 类使用 final 关键字的例子: final class Person{ ...... } final 定义的类被继承时会提示如下错误: Fatal error: Class Studen

Android下将图片加载到内存中

Android的系统的标准默认每个应用程序分配的内存是16M.所以来说是非常宝贵的,在创建应用的时候要尽可能的去节省内存,但是在加载一些大的文件的时候,比如图片是相当耗内存的,一个1.3M的图片,分辨率是2560X1920(宽X高)图片当加载到手机内存的时候就会请求19M的一块内存,这是远远超出了系统自带的内存空间,这时候应用程序就会挂掉,所以我们要进行图片的缩放处理,下面我就来带大家创建一个用来图片缩放的应用: 应用效果图如下: 核心代码的实现: package com.examp.loadp

iOS图片加载到内存中占用内存情况

我的测试结果: 图片占用内存   图片尺寸           .png文件大小 1MB              512*512          316KB 4MB              1024*1024      940KB 16MB            2048*2048      2.5MB 1.11MB         512*568 693KB          320*568          186KB 2.773MB       640*1136        664

PHP的类文件自动加载机制

搜集于网络,学习php的类的自动加载机制,在实际大型项目中其重要性尤为突出. PHP的类自动加载机制 在PHP开发过程中,如果希望从外部引入一个class,通常会使用include和require方法,去把定义这个class的文件包含进来.这个在小规模开发的时候,没什么大问题.但在大型的开发项目中,这么做会产生大量的require或者include方法调用,这样不因降低效率,而且使得代码难以维护,况且require_once的代价很大. 在PHP5之前,各个PHP框架如果要实现类的自动加载,一般

__autoload() 类文件自动加载函数

这个魔术方法是用来自动加载程序所用到类文件的PHP源文件,这样就避免了我们一个一个自动去require或者include了,这个函数会在试图使用尚未被定义的类时自动调用.通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类,但是我最近看过一篇文章,上面说__autoload()的效率不是很高.以下是示例代码: 1 <?php 2 功能:在当前页使用类时自动加载该类的文件 3 参数$className 为类的名称 可自定义 4 5 */ 6 7 function __auto

ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-04 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的描述 加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: 另一种是动态链接,是指库函数的代码并不进入应用软件的目标映像,应用软件在编译/链接阶段并

可执行程序加载到内存的过程

http://blog.csdn.net/q_l_s/article/details/52594252 在linux中,程序的加载,涉及到两个工具,linker 和loader.Linker主要涉及动态链接库的使用,loader主要涉及软件的加载. 1.  exec执行一个程序 2.  elf为现在非常流行的可执行文件的格式,它为程序运行划分了两个段,一个段是可以执行的代码段,它是只读,可执行:另一个段是数据段,它是可读写,不能执行. 3.  loader会启动,通过mmap系统调用,将代码端和

BitmapFactory.Options解决Android加载图片内存溢出的问题

BitmapFactory.Options解决Android加载图片内存溢出的问题 1. 在Android软件开发过程中,图片处理是经常遇到的. 在将图片转换成Bitmap的时候,由于图片的大小不一样,当遇到很大的图片的时候会出现超出内存的问题,为了解决这个问题Android API提供了BitmapFactory.Options这个类. 2. 由于Android对图片使用内存有限制,若是加载几兆的大图片便内存溢出.Bitmap会将图片的所有像素(即长x宽)加载到内存中,如果图片分辨率过大,会直