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



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

我相信我看到了一些关于"进行系统调用"的东西(尽管我今天没有找到,浏览了几次列表)。这些"特殊"调用是否有自己的代码,由VM直接委托(不知道技术上怎么说)给操作系统?我知道有很多方法可以打开字节码,但我想要一个通用的解释,而不是几周的学习高级字节码。

没有打开端口或在屏幕上绘制图形的字节码。有一些类可以执行这些任务。这些类具有本机方法,这些方法是用C(或任何其他可以编译为本机库的语言)编写的,并且由于它们是本机的,它们可以访问操作系统的网络和图形库来执行这些任务。你正在实例化这些类并调用它们的一些方法。Java字节码提供了用于实例化类和调用对象方法的字节码。如果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或UNIX/Linux系统上的OS x这个函数可以调用另一个函数(等等),但是是一个简单的C函数调用写点东西给一个C FILE *流或一个文件描述符(这只是一个用C int)。这可能是一个printf()/fprintf()或者puts()/fputs()称之为写入stdout STDOUT_FILENO write()称之为写道。在Windows中,它通常是对WriteFile()的调用,尽管它也可能是printf()/fprintf()(这些是C标准函数,所有平台都必须支持它们)。

最新更新