この記事の内容は、Java の可変長パラメータとは何なのかを紹介することです。 foreach ループの原理は何ですか?困っている友人は参考にしていただければ幸いです。
1. 構文シュガー
構文シュガーは、ほぼすべての言語である程度プログラマに提供される便利な構文です。開発コードは、コンパイル中に # によって実装されるちょっとしたトリックです。これらの構文を処理するために使用され、開発者はそれらを直接かつ便利に使用できます。 これらのシンタックス シュガーは大幅な機能向上を提供しませんが、パフォーマンスを向上させたり、構文の厳密さを改善したり、コーディング エラーの可能性を減らしたりする可能性があります。 。 Java は、ジェネリックス、オートボックス化、自動アンボックス化、foreach ループ、可変長パラメーター、内部クラス、列挙型クラス、アサーションなど、多くの構文糖衣をユーザーに提供します。
2. 可変長パラメーター
まず、可変長パラメーターについて説明します。コードの一部を見てみましょう。
public static void main(String[] args) { print("000", "111", "222", "333"); } public static void print(String... strs) { for (int i = 0; i < strs.length; i++) { System.out.println(strs[i]); } }
print メソッドのパラメータは、受信する文字列の数が変数であることを意味します。 コードの実行結果を見てください:
000 111 222 333配列トラバーサルを使用しました。このメソッドは入力パラメーターを正常にトラバースしました。これは 2 つの問題を示しています。
1. 配列をトラバースするメソッドを使用して、可変長パラメーターをトラバースできます。
##2. 変数パラメータは配列を使用して実装されますこの場合、実際には次のように main 関数を書くことができます。全く問題ありません:
String[] strs = {"000", "111", "222", "333"}; print(strs);配列を直接渡したほうが良いのではないでしょうか?問題は、配列の長さを指定する必要があることです。今回は 2 つの文字列を渡し、次回は 3 つの文字列を渡したい場合はどうすればよいでしょうか。 最後に、可変長パラメータはメソッド パラメータ リストの最後のパラメータとして使用する必要があり、メソッド パラメータ リストに存在できる可変長パラメータは
1 つだけであることに注意してください。 。
3. foreach ループの原理これは、私が原理を勉強するきっかけとなった foreach ループの以前の使用方法です。その理由は、約 2 か月前に自分で ArrayList を作成し、その効果を確認するために foreach ループを使用しようとしたのですが、null ポインター例外が報告されたためです。この記事では、foreach ループの原理について説明します。まず、次のコードを見てください。
public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("111"); list.add("222"); for (String str : list) { System.out.println(str); } }結果については説明しません。誰もが知っています。 Java がこの foreach ループをどのように処理するかを見てください。 javap で逆コンパイルします。
F:\代码\MyEclipse\TestArticle\bin\com\xrq\test21>javap -verbose TestMain.classクラス情報、シンボル参照、バイトコード情報など、多くの逆コンパイルされたコンテンツがインターセプトされます。 ##
public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 0: new #16 // class java/util/ArrayList 3: dup 4: invokespecial #18 // Method java/util/ArrayList."<in it>":()V 7: astore_1 8: aload_1 9: ldc #19 // String 111 11: invokeinterface #21, 2 // InterfaceMethod java/util/List. add:(Ljava/lang/Object;)Z 16: pop 17: aload_1 18: ldc #27 // String 222 20: invokeinterface #21, 2 // InterfaceMethod java/util/List. add:(Ljava/lang/Object;)Z 25: pop 26: aload_1 27: invokeinterface #29, 1 // InterfaceMethod java/util/List. iterator:()Ljava/util/Iterator;New、dup、invokespecial は元々バイトコード命令テーブルに定義された命令であり、仮想マシンはこれらの命令に基づいて指定された C コードを実行します。各命令の機能を完了します。重要なのは、行 21 と 22 です。イテレータを見たので、次の結論に達しました。
コンパイラは、コンパイル中に # に対して自動的にコンパイルします。 ##それぞれこのキーワードの使用は、ターゲット の # に変換されます。 ##イテレータの使用法,これが foreach ループの原理です。 さらに、さらに 2 つの結論が導き出されます: #1. foreach ループを使用して ArrayList を走査できる理由は、ArrayList がすべて存在するためです。 List は Collection のサブインターフェイスであり、Collection は Iterable のサブインターフェイスです。ArrayList の親クラスである AbstractList は、Iterable インターフェイスのイテレータ メソッドを正しく実装します。以前は、私が作成した ArrayList が Iterable インターフェイスを実装していなかったため、foreach ループを使用して null ポインタ例外を直接報告していました。
2、任何一个集合,无论是JDK提供的还是自己写的,只要想使用foreach循环遍历,就必须正确地实现Iterable接口实际上,这种做法就是23中设计模式中的迭代器模式。
数组呢?
上面的讲完了,好理解,但是不知道大家有没有疑问,至少我是有一个疑问的:数组并没有实现Iterable接口啊,为什么数组也可以用foreach循环遍历呢?先给一段代码,再反编译:
public static void main(String[] args) { int[] ints = {1,2,3,4,5}; for (int i : ints) System.out.println(i); }
同样反编译一下,看一下关键的信息:
0: iconst_2 1: newarray int 3: dup 4: iconst_0 5: iconst_1 6: iastore 7: dup 8: iconst_1 9: iconst_2 10: iastore 11: astore_1 12: aload_1 13: dup 14: astore 5 16: arraylength 17: istore 4 19: iconst_0 20: istore_3 21: goto 39 24: aload 5 26: iload_3 27: iaload 28: istore_2 29: getstatic #16 // Field java/lang/System.out:Ljav a/io/PrintStream; 32: iload_2 33: invokevirtual #22 // Method java/io/PrintStream.prin tln:(I)V 36: iinc 3, 1 39: iload_3 40: iload 4 42: if_icmplt 24 45: return
这是完整的这段main函数对应的45个字节码指令,因为这涉及一些压栈、出栈、推送等一些计算机原理性的内容且对于这些字节码指令的知识的理解需要一些C++的知识,所以就不解释了。简单对照字节码指令表之后,我个人对于这45个字节码的理解是Java将对于数组的foreach循环转换为对于这个数组每一个的循环引用。
总结:以上就是本篇文的全部内容,希望能对大家的学习有所帮助。更多相关教程请访问Java视频教程,java开发图文教程,bootstrap视频教程!
以上がJavaの可変長パラメータとは何ですか? foreach ループの原理は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。