考虑以下(Sourced primarily from here):
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler( );
JavaFileManager manager = new MemoryFileManager( compiler.getStandardFileManager( null, null, null ) );
compiler.getTask( null, manager, null, null, null, sourceScripts ).call( ); //sourceScripts is of type List<ClassFile>
以下文件管理器:
public class MemoryFileManager extends ForwardingJavaFileManager< JavaFileManager > {
private HashMap< String, ClassFile > classes = new HashMap<>( );
public MemoryFileManager( StandardJavaFileManager standardManager ) {
super( standardManager );
}
@Override
public ClassLoader getClassLoader( Location location ) {
return new SecureClassLoader( ) {
@Override
protected Class< ? > findClass( String className ) throws ClassNotFoundException {
if ( classes.containsKey( className ) ) {
byte[ ] classFile = classes.get( className ).getClassBytes( );
System.out.println(new String(classFile, "utf-8"));
return super.defineClass( className, classFile, 0, classFile.length );
} else throw new ClassNotFoundException( );
}
};
}
@Override
public ClassFile getJavaFileForOutput( Location location, String className, Kind kind, FileObject sibling ) {
if ( classes.containsKey( className ) ) return classes.get( className );
else {
ClassFile classObject = new ClassFile( className, kind );
classes.put( className, classObject );
return classObject;
}
}
}
public class ClassFile extends SimpleJavaFileObject {
private byte[ ] source;
protected final ByteArrayOutputStream compiled = new ByteArrayOutputStream( );
public ClassFile( String className, byte[ ] contentBytes ) {
super( URI.create( "string:///" + className.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE );
source = contentBytes;
}
public ClassFile( String className, CharSequence contentCharSequence ) throws UnsupportedEncodingException {
super( URI.create( "string:///" + className.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE );
source = ( ( String )contentCharSequence ).getBytes( "UTF-8" );
}
public ClassFile( String className, Kind kind ) {
super( URI.create( "string:///" + className.replace( '.', '/' ) + kind.extension ), kind );
}
public byte[ ] getClassBytes( ) {
return compiled.toByteArray( );
}
public byte[ ] getSourceBytes( ) {
return source;
}
@Override
public CharSequence getCharContent( boolean ignoreEncodingErrors ) throws UnsupportedEncodingException {
return new String( source, "UTF-8" );
}
@Override
public OutputStream openOutputStream( ) {
return compiled;
}
}
在compile.getTask()。call()上逐步执行代码,这里发生的第一件事就是调用getJavaFileForOutput(),然后调用getClassLoader()方法来加载类,编译后的字节写入控制台。
为什么getClassLoader()方法中的println会产生我工作的编译字节码的合并(主要是字符串,看起来实际的字节码指令关键字不在这里)和随机乱码?这让我相信我使用的UTF太短,所以我尝试了UTF-16,它看起来或多或少相似。如何将字节编码回文本?我知道使用SimpleJavaFileManager会很简单但我需要能够使用这个缓存示例(当然没有可能的内存泄漏)用于性能目的。
编辑: 是的,编译后的代码可以完成类加载和运行。
答案 0 :(得分:1)
为什么getClassLoader()方法中的println会产生我工作的编译字节码的合并(主要是字符串,看起来实际的字节码指令关键字不在这里)和随机乱码?
如果没有看到所谓的&#34;随机乱码&#34;,我会猜测你所看到的是一个格式良好的二进制内容,它已经被解码了#34;作为某些字符集中的字符串。
那无法上班。它是一种二进制格式,您不能期望将其转换为文本,并将其显示为可读的内容。
(对于它的价值,一个&#34; .class&#34;文件不包含JVM操作码的关键字,除了#34; .exe&#34;文件将包含机器的关键字说明。它是二进制!)
如果要以文本形式查看已编译的代码,请将该字节数组中的字节保存到文件中,然后使用javap
实用程序查看它。 (我将让您查找javap
命令的命令行语法...)