4

私はJavaバイトコードのリストとウィキペディアを見ていますが、それらはすべて基本的な操作(ブランチ、プッシュ、ポップ、キャストなど)のようです。そして、多くの記事がこれらの基本的な例を使用しています。しかし、コンソールから行を読み取ったり、新しいJButtonを作成したりすると、どうなりますか?ポートを開くためのバイトコードはどこにありますか?

「システムコールをかける」ための何かを見たと思います(今日は見つかりませんでしたが、リストを何度か調べました)。これらの「特別な」呼び出しには独自のコードがあり、VMによってOSに直接委任されますか(技術的にはそれを言う方法がわかりません)?バイトコードを開く方法があることは知っていますが、高度なバイトコードを数週間学習するのではなく、一般的な説明を探しています。

4

1 に答える 1

7

ポートを開いたり、画面にグラフィックを描画したりするためのバイトコードはありません。これらのタスクを実行するクラスがあります。これらのクラスにはネイティブメソッドがあります。これらはC(またはネイティブライブラリにコンパイルできるその他の言語)で記述されたメソッドであり、ネイティブであるため、オペレーティングシステムのネットワークおよびgraphcisライブラリにアクセスしてこれらのタスクを実行できます。したがって、これらのクラスをインスタンス化し、それらのメソッドのいくつかを呼び出します。Javaバイトコードは、クラスをインスタンス化し、オブジェクトのメソッドを呼び出すためのバイトコードを提供します。JVMは、これがネイティブメソッドであることを認識すると、このメソッドに属するネイティブコードを呼び出し、このネイティブコードは、CまたはC++プログラムが実行できるほとんどすべてのことを実行できます。

したがって、たとえば、System.out.printlnJavaで呼び出すと、おおよそ次のようになります。

System静的変数を持つクラスですout。この変数は、メソッドが実行されるjava.io.PrintStream前にJVMによってすでに作成されているタイプのオブジェクトを指します。main変数は次の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、OSXのいずれであるかによって異なります。UNIX/Linuxシステムでは、この関数は別の関数(など)を呼び出す場合がありますが、どこかにあります。 CFILE *ストリームまたはファイル記述子( Cの場合のみ)に何かを書き込むための単純なC関数呼び出しint。したがって、またはに書き込む呼び出し、またはにprintf()/fprintf()書き込むputs()/fputs()呼び出しである可能性があります。Windowsでは、通常はへの呼び出しですが、(C標準関数であり、すべてのプラットフォームでサポートされている必要があります)の場合もあります。stdoutwrite()STDOUT_FILENOWriteFile()printf()/fprintf()

于 2013-01-21T00:10:06.387 に答える