4

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

我相信我看到了一些关于“进行系统调用”的东西(虽然我今天没有找到它,浏览了几次列表)。这些“特殊”调用是否有自己的代码,由虚拟机直接委托(不知道从技术上怎么说)给操作系统?我知道有一些方法可以打开字节码,但我正在寻找一个一般性的解释,而不是数周的学习高级字节码。

4

1 回答 1

7

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

因此,例如,如果您System.out.println在 Java 中调用,则大致会发生以下情况:

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

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 将在所有加载的库中搜索一个带有 name 的符号(在这种情况下,符号表示函数名)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 函数调用,用于将内容写入 CFILE *流或文件描述符(这只是intC 中的一个)。所以它可能是一个printf()/fprintf()或一个puts()/fputs()写入到的调用stdout或一个写入到的write()调用STDOUT_FILENO。在 Windows 中,它通常是对 的调用WriteFile(),尽管它也可能是 a printf()/fprintf()(这些是 C 标准函数,所有平台都必须支持它们)。

于 2013-01-21T00:10:06.387 回答