JAva ioシリーズ17のSystem.out.println(「hello world」)原理
7090 ワード
Javaの最初のプログラムは「hello world」です
上のプログラムはいったいどのようにスクリーンに「hello world」を出力しますか?これが本来説明すべき内容であるSystemです.out.println(「hello world」)の原理.
まずシステムを見てみましょうout.printlnのプロセス.まずシステムを見てみましょうJAvaのoutの定義は、次のようになります.
ここから,(01)outはSystemであることが分かった.JAvaの静的変数.(02)そしてoutはPrintStreamオブジェクト、PrintStreamである.JAvaには、リロードされたprintln()メソッドがたくさんあります.
OK、outがPrintStreamオブジェクトであることがわかりました.次に、どのように初期化されたのか、画面出力にどのように関連付けられているのかを見てみましょう.まずシステムを見てみましょうJAvaのinitializeSystemClass()メソッド.1.initializeSystemClass()のソースコードは、out部分を赤色にマークする
上の赤いコード部分、すなわちFileOutputStream fdOut=new FileOutputStream(FileDescriptor.out);setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));この2つの言葉を細分化すると、第1ステップFileDescriptor fd=FileDescriptorに分けられる.out;ステップ2 FileOutputStream fdOut=new FileOutputStream(fd);ステップ3 BufferedOutputStream bufOut=new BufferedOutputStream(fdOut,128);ステップ4 PrintStreams ps=new PrintStream(bufout,true);ステップ5 setOut 0(ps);説明:(01)ステップ1、FileDescriptorを取得する.JAvaの静的メンバーout,outはFileDescriptorオブジェクトであり,実際には「標準出力(画面)」の識別子である.FileDescriptorの詳細については、ブログ「java ioシリーズ09のFileDescriptorまとめ」を参照してください.FileDescriptor.JAvaでFileDescriptorとout関連コードは以下の通りです.
(02)「標準出力(画面)」に対応する「ファイル出力ストリーム」を作成する.(03)ファイル出力ストリームに対応するバッファ出力ストリームを作成する.ファイル出力ストリームにバッファ機能を追加することを目的としています.(04)「バッファ出力ストリーム」に対応する「プリント出力ストリーム」を作成する.「バッファ出力ストリーム」にprint()、println()、printf()などの便利な印刷インタフェースを提供することを目的とする.印刷出力を容易かつ迅速に行うことができます.(05)setout 0(ps)を実行する.
次に,ステップ5のsetOut 0(ps)を解析する.システムを表示します.JAvaのsetOut 0()の宣言は、次のとおりです.
ここからsetout 0()はnativeローカルメソッドであることが分かった.Openjdkでは、次のように対応するソースコードを見つけることができます.
説明:これはJNI関数で、簡単な分析を行います.(01)関数名JNIEXPORT void JNICALL Java_java_lang_System_setOut 0(JNIEnv*env,jclass cla,jobject stream)これはJNIの静的登録方法、Java_java_lang_System_setOut 0(JNIEnv*env,jclass cla,jobject stream)とSystem.JAvaのsetOut 0(PrintStream out)関連付け;また、パラメータstreamはパラメータoutに対応する.簡単に言えばsetOut 0()を呼び出しますが、実際にはJava_を呼び出します.java_lang_System_setOut0().JNIの詳細については、ブログ「Android JNIとNDK学習(02)--静的にJNIを実現する」を参照してください.
(02) jfieldID fid = (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");この言葉の役割はSystemを取得することです.JAvaの静的メンバーoutのjfieldID、「Ljava/io/printStream;」説明outはjavaです.io.PrintStreamオブジェクト.outのjfieldIDを取得する役割は、「outのjfielID」を操作することでoutの値を変更する必要があることです.
(03) (*env)->SetStaticObjectField(env,cla,fid,stream);この文の役割はfid(fidはoutのjfieldID)に対応する静的メンバーの値をstreamに設定することである.streamは私たちがJavaに伝えたものです.java_lang_System_setout 0()のパラメータ、すなわちsetout 0に渡されるパラメータ.
上記の内容をまとめる.setout 0(PrintStreamps)の役割は、psをSystemに設定することであることを知っています.JAvaのout静的変数.
前にも言ったようにoutは機械の「標準出力(画面)」のファイル識別子である.ファイル識別子は、FileDescriptorとして一般的に理解できます.outは代表的な「標準出力」です.したがって、initializeSystemClass()では、上の5つのステップで「FileDescriptor.out」をカプセル化します.パッケージ化されたシステムIn既存のバッファ機能;print()、println()、printf()などの便利な操作インタフェースもあります.
1 public class HelloWorld {
2 public static void main(String[] args) {
3 System.out.println("hello world");
4 }
5 }
上のプログラムはいったいどのようにスクリーンに「hello world」を出力しますか?これが本来説明すべき内容であるSystemです.out.println(「hello world」)の原理.
まずシステムを見てみましょうout.printlnのプロセス.まずシステムを見てみましょうJAvaのoutの定義は、次のようになります.
1 public final class System {
2 ...
3
4 public final static PrintStream out = null;
5
6 ...
7 }
ここから,(01)outはSystemであることが分かった.JAvaの静的変数.(02)そしてoutはPrintStreamオブジェクト、PrintStreamである.JAvaには、リロードされたprintln()メソッドがたくさんあります.
OK、outがPrintStreamオブジェクトであることがわかりました.次に、どのように初期化されたのか、画面出力にどのように関連付けられているのかを見てみましょう.まずシステムを見てみましょうJAvaのinitializeSystemClass()メソッド.1.initializeSystemClass()のソースコードは、out部分を赤色にマークする
1 private static void initializeSystemClass() {
2
3 props = new Properties();
4 initProperties(props); // initialized by the VM
5
6 sun.misc.VM.saveAndRemoveProperties(props);
7
8 lineSeparator = props.getProperty("line.separator");
9 sun.misc.Version.init();
10
11 FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
12 FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
13 FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
14 setIn0(new BufferedInputStream(fdIn));
15 setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
16 setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));
17
18 loadLibrary("zip");
19
20 Terminator.setup();
21
22 sun.misc.VM.initializeOSEnvironment();
23
24 Thread current = Thread.currentThread();
25 current.getThreadGroup().add(current);
26
27 setJavaLangAccess();
28
29 sun.misc.VM.booted();
30 }
上の赤いコード部分、すなわちFileOutputStream fdOut=new FileOutputStream(FileDescriptor.out);setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));この2つの言葉を細分化すると、第1ステップFileDescriptor fd=FileDescriptorに分けられる.out;ステップ2 FileOutputStream fdOut=new FileOutputStream(fd);ステップ3 BufferedOutputStream bufOut=new BufferedOutputStream(fdOut,128);ステップ4 PrintStreams ps=new PrintStream(bufout,true);ステップ5 setOut 0(ps);説明:(01)ステップ1、FileDescriptorを取得する.JAvaの静的メンバーout,outはFileDescriptorオブジェクトであり,実際には「標準出力(画面)」の識別子である.FileDescriptorの詳細については、ブログ「java ioシリーズ09のFileDescriptorまとめ」を参照してください.FileDescriptor.JAvaでFileDescriptorとout関連コードは以下の通りです.
1 public final class FileDescriptor {
2
3 private int fd;
4
5 public static final FileDescriptor out = new FileDescriptor(1);
6
7 private FileDescriptor(int fd) {
8 this.fd = fd;
9 useCount = new AtomicInteger();
10 }
11
12 ...
13 }
(02)「標準出力(画面)」に対応する「ファイル出力ストリーム」を作成する.(03)ファイル出力ストリームに対応するバッファ出力ストリームを作成する.ファイル出力ストリームにバッファ機能を追加することを目的としています.(04)「バッファ出力ストリーム」に対応する「プリント出力ストリーム」を作成する.「バッファ出力ストリーム」にprint()、println()、printf()などの便利な印刷インタフェースを提供することを目的とする.印刷出力を容易かつ迅速に行うことができます.(05)setout 0(ps)を実行する.
次に,ステップ5のsetOut 0(ps)を解析する.システムを表示します.JAvaのsetOut 0()の宣言は、次のとおりです.
private static native void setOut0(PrintStream out);
ここからsetout 0()はnativeローカルメソッドであることが分かった.Openjdkでは、次のように対応するソースコードを見つけることができます.
1 JNIEXPORT void JNICALL
2 Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
3 {
4 jfieldID fid =
5 (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
6 if (fid == 0)
7 return;
8 (*env)->SetStaticObjectField(env,cla,fid,stream);
9 }
説明:これはJNI関数で、簡単な分析を行います.(01)関数名JNIEXPORT void JNICALL Java_java_lang_System_setOut 0(JNIEnv*env,jclass cla,jobject stream)これはJNIの静的登録方法、Java_java_lang_System_setOut 0(JNIEnv*env,jclass cla,jobject stream)とSystem.JAvaのsetOut 0(PrintStream out)関連付け;また、パラメータstreamはパラメータoutに対応する.簡単に言えばsetOut 0()を呼び出しますが、実際にはJava_を呼び出します.java_lang_System_setOut0().JNIの詳細については、ブログ「Android JNIとNDK学習(02)--静的にJNIを実現する」を参照してください.
(02) jfieldID fid = (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");この言葉の役割はSystemを取得することです.JAvaの静的メンバーoutのjfieldID、「Ljava/io/printStream;」説明outはjavaです.io.PrintStreamオブジェクト.outのjfieldIDを取得する役割は、「outのjfielID」を操作することでoutの値を変更する必要があることです.
(03) (*env)->SetStaticObjectField(env,cla,fid,stream);この文の役割はfid(fidはoutのjfieldID)に対応する静的メンバーの値をstreamに設定することである.streamは私たちがJavaに伝えたものです.java_lang_System_setout 0()のパラメータ、すなわちsetout 0に渡されるパラメータ.
上記の内容をまとめる.setout 0(PrintStreamps)の役割は、psをSystemに設定することであることを知っています.JAvaのout静的変数.
前にも言ったようにoutは機械の「標準出力(画面)」のファイル識別子である.ファイル識別子は、FileDescriptorとして一般的に理解できます.outは代表的な「標準出力」です.したがって、initializeSystemClass()では、上の5つのステップで「FileDescriptor.out」をカプセル化します.パッケージ化されたシステムIn既存のバッファ機能;print()、println()、printf()などの便利な操作インタフェースもあります.