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

256个java字节码如何转换为java所做的一切(图形、IO等),java,bytecode,Java,Bytecode,我正在查看java字节码列表和Wikipedia,它们似乎都是基本操作(分支、推送、pop、cast等)。许多文章都使用这些基本示例。但是当我从控制台读取一行或创建一个新的JButton时会发生什么呢?打开端口的字节码在哪里 我相信我看到了一些关于“进行系统调用”的东西(尽管我今天没有找到,只是浏览了几次列表)。这些“特殊”调用是否有自己的代码,由VM直接委托给操作系统(技术上不知道怎么说)?我知道有很多方法可以打开字节码,但我想要的是一个一般性的解释,而不是几周的高级字节码学习。没有字节码可以

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


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

没有字节码可以打开端口或在屏幕上绘制图形。有些类执行这些任务。这些类具有本机方法,这些方法是用C编写的(或可以编译为本机库的任何其他语言),由于它们是本机的,因此它们可以访问操作系统的网络和图形库来执行这些任务。因此,您正在实例化这些类并调用它们的一些方法。Java字节码提供用于实例化类和调用对象方法的字节码。如果JVM看到这是一个本地方法,它将调用属于该方法的本机代码,并且这个本地代码可以做很多C或C++程序所能做的事情。p> 例如,如果在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));
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);
}
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);
}
方法setOut0定义为

private static native void setOut0(PrintStream out);
这意味着setOut0是一种本机方法,用C或其他一些语言编写,可以编译并链接到本机库,但至少Java和本机库之间的接口通常是用C编写的

Java将在所有加载的库中搜索名为
Java\u Java\u lang\u System\u setOut0
的符号(在这种情况下,符号表示函数名),这是
Java\u ClassName\u MethodName
,并调用它。我为该方法找到的示例C代码如下所示:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
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);
}
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);
}
然而,这不是真正的魔法,真正的魔法发生在别处
PrintStream.write()
调用
BufferedWriter.write()
。此方法再次调用
OutputStreamWriter.write()
(不是直接调用,而是迟早会在那里结束),并且此方法调用
streamncoder.write()
。哇,追踪那个电话越来越难了。
streamncoder
调用
BufferedOutputStream.write()
,这个调用
FileOutputStream.write()
,这个调用
FileOutputStream.writeBytes()
,最后,我们终于到了
FileOutputStream.writeBytes()
是本机方法。它看起来像这样:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
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);
}
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
文件*
流或文件描述符(这在C中只是一个
int
)因此它可以是
printf()/fprintf()
put()/fputs()
调用,写入
stdout
write()
调用,写入
stdout\u文件号
。在Windows中,它通常是调用
WriteFile()
,但也可以是
printf()/fprintf()
(这些是C标准函数,所有平台都必须支持它们)。

有限数量的操作码如何转换为CPU所做的一切?有限数量的数学运算符如何转换为无限数量的代数方程?有限数量的单词如何转换为[near?]无限组短语?你可能会发现这很有趣:你可能想学习一点汇编语言和操作码。指令集很小,但可以从中派生出很多东西。@Raekye从理论上解决同一组问题所需要的是(以及访问相同资源的能力)当然,仅仅因为语言是TC并不实用。但是,CPU和JVM工作在同一个模型上。(注意,JVM需要将一些操作委托给JNI:实际I/O-例如,外部资源-操作是JVM委托给适用本机接口的一个很好的例子。)@Raekye CPU使用内存映射IO。例如,您的显示器是一个已映射到CPU内存的输出设备。通过访问该内存地址,您可以操纵显示器的像素。这可以使用汇编轻松完成(当然,复杂的动画会很复杂)因此,当我调用
System.out.println
时,实际发生了什么?是什么字节码开始了本机代码?(我将对其进行分离,但我也对所有映射的工作方式感兴趣)编辑:所以我看到了
GETSTATIC java/lang/System.out:Ljava/io/PrintStream
。我猜JVM sorta侦听本机类,并分别处理这些函数调用?如果你想了解真正精细的细节,你应该先了解微处理器。为了geto To java,已经完成了几层抽象。
如果JVM发现这是一个本机方法,它将调用本机C代码
ah,这是我遗漏的一点。我已经谈到了汇编,但主要想知道“更复杂”在哪里字节码进来了。无论如何,这对我来说是清白的。谢谢你的回复和链接!@Raekye我将更新一个关于System.out.println的问题,这是一个很好的例子:-)