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

Rae*_*kye 2 java bytecode

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

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

Mec*_*cki 5

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

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

System是一个带有静态变量的类out.此变量指向一个类型的对象,该对象java.io.PrintStreammain执行方法之前已由JVM创建.该out变量初始化是这样的:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
Run Code Online (Sandbox Code Playgroud)

方法setOut0定义为

private static native void setOut0(PrintStream out);
Run Code Online (Sandbox Code Playgroud)

这意味着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);
}
Run Code Online (Sandbox Code Playgroud)

然而,这不是真正的魔法,真正的魔法发生在其他地方.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);
}
Run Code Online (Sandbox Code Playgroud)

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