256个java字节码如何转换为java所做的一切(图形,IO等)

时间:2013-01-20 23:54:47

标签: java bytecode

我正在查看java字节码列表和维基百科,它们似乎都是基本操作(分支,推送,弹出,转换等)。许多文章都使用这些基本示例。但是当我从控制台读取一行或创建一个新的JButton时会发生什么?打开端口的字节码在哪里?

我相信我看到了“拨打系统电话”的内容(虽然我今天没有找到它,但却多次浏览列表)。这些“特殊”调用是否有自己的代码,这些代码由VM直接委托给操作系统(技术上不知道如何说)?我知道有办法打开字节码,但我正在寻找一般性的解释,而不是数周学习高级字节码。

1 个答案:

答案 0 :(得分:5)

没有用于打开端口或将图形绘制到屏幕的字节代码。有些类可以执行这些任务。这些类具有本机方法,即用C语言编写的方法(或可以编译为本机库的任何其他语言),并且由于它们是本机的,因此它们可以访问操作系统的网络和graphcis库来执行这些任务。所以你要实例化这些类并调用它们的一些方法。 Java Byte Code提供了用于实例化类和调用对象方法的字节代码。如果JVM发现这是一个本机方法,它将调用属于此方法的本机代码,并且此本机代码可以执行C或C ++程序可以执行的任何操作。

例如,如果您在Java中调用System.out.println粗略,则会发生以下情况:

System是一个带有静态变量out的类。此变量指向类型为java.io.PrintStream的对象,该对象在执行main方法之前已由JVM创建。 out变量初始化如下:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));

方法setOut0定义为

private static native void setOut0(PrintStream out);

这意味着setOut0是一个本机方法,用C语言编写,或者可以编译并链接到本机库的其他语言,但至少Java和这个库之间的接口通常用C语言编写。

Java将在所有加载的库中搜索名称为Java_java_lang_System_setOut0的符号(在这种情况下,符号表示函数名称),这是Java_ClassName_MethodName并调用它。我找到的这个方法的示例C代码如下所示:

JNIEXPORT void JNICALL
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
{
    jfieldID fid =
        (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
    if (fid == 0)
        return;
    (*env)->SetStaticObjectField(env,cla,fid,stream);
}

然而,这不是真正的魔法,真正的魔法发生在其他地方。 PrintStream.write()来电BufferedWriter.write()。此方法再次调用OutputStreamWriter.write()(不是直接调用,但迟早会在那里结束),此方法调用StreamEncoder.write()。哇,跟踪这个电话越来越难了。 StreamEncoder调用BufferedOutputStream.write(),此调用FileOutputStream.write(),此调用FileOutputStream.writeBytes(),最后,我们终于来了! FileOutputStream.writeBytes()原生方法。它看起来像这样:

JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
    jobject this, jbyteArray bytes, jint off, jint len) {
    writeBytes(env, this, bytes, off, len, fos_fd);
}

所以它调用一个名为writeBytes的函数,这个函数看起来会有所不同,具体取决于你的操作系统,例如:无论是Windows,Linux还是OS X.在UNIX / Linux系统上,此函数可以调用另一个函数(依此类推),但某处是一个简单的C函数调用,可以将内容写入C FILE *流或文件描述符(在C中只是int)。因此,printf()/fprintf()puts()/fputs()来电可以写入stdout或写入write()的{​​{1}}来电。在Windows中,它通常是对STDOUT_FILENO的调用,虽然它也可以是WriteFile()(这些是C标准函数,所有平台都必须支持它们)。