我正在查看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标准函数,所有平台都必须支持它们)。