我正在查看java字节码列表和维基百科,它们似乎都是基本操作(分支,推送,弹出,转换等)。许多文章都使用这些基本示例。但是当我从控制台读取一行或创建一个新的JButton时会发生什么?打开端口的字节码在哪里?
我相信我看到了“拨打系统电话”的内容(虽然我今天没有找到它,但却多次浏览列表)。这些“特殊”调用是否有自己的代码,这些代码由VM直接委托给操作系统(技术上不知道如何说)?我知道有办法打开字节码,但我正在寻找一般性的解释,而不是数周学习高级字节码。
答案 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标准函数,所有平台都必须支持它们)。