首頁 > Java > java教程 > 主體

java中什麼是可變長度參數? foreach循環原理是什麼?

青灯夜游
發布: 2018-10-19 17:21:01
轉載
2208 人瀏覽過

本篇文章帶給大家的內容是介紹java中什麼是可變長度參數? foreach循環原理是什麼?有一定的參考價值,有需要的朋友可以參考一下,希望對你們有幫助。

一、語法糖 

語法糖是幾乎每種語言或多或少都提供過的一些方便程式設計師開發程式碼的語法,它只是編譯器#實現的一些小把戲罷了,編譯期間以特定的字節碼或特定的方式對這些語法做一些處理,開發者就可以直接方便地使用了。 這些語法糖雖然不會提供實質的功能改進,但是它們或能提高性能、或能提升語法的嚴謹性、或能減少編碼出錯的機會 。 Java提供給了使用者大量的語法糖,例如泛型、自動裝箱、自動拆箱、foreach循環、變長參數、內部類別、枚舉類別、斷言(assert)等。

二、可變長參數

#先講可變長度參數,看一段程式碼:

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方法的參數的意思是表示傳入的String個數是不定的,看一下程式碼的運行結果:

000
111
222
333
登入後複製

我用陣列遍歷的方式成功地將輸入的參數遍歷出來了,這說明兩個問題:

1、可以使用遍歷數組的方式去遍歷可變長參數

2、可變參數是利用陣列實現的

#既然這樣,那我其實main函數也可以這麼寫,完全可以:

String[] strs = {"000", "111", "222", "333"};
print(strs);
登入後複製

那直接傳入一個陣列不就好了?問題是,陣列是要指定長度的,萬一這次我想傳2個String,下次想傳3個String怎麼辦呢?

最後,注意一點,可變長度參數必須作為方法參數列表中的最後一個參數且方法參數列表中只能有一個可變長度參數

三、foreach循環原理

#以前對foreach循環就是這樣用著,觸動我去研究foreach循環的原理的原因是大概兩個月前,自己寫了一個ArrayList,想用foreach循環遍歷一下看一下寫的效果,結果報了空指標異常。本文就寫寫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);
    }
}
登入後複製

用foreach循環去遍歷這個list,結果就不說了,都知道。看一下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這兩行就可以了,看到了一個iterator,所以得出結論:在編譯的時候編譯器會自動將對foreach#這個關鍵字的使用轉化為對目標的#迭代器的使用這就是foreach迴圈的原理。 進而,我們再得出兩個結論:

1、ArrayList之所以能使用foreach循環遍歷,是因為ArrayList所有的List都是Collection的子接口,而Collection是Iterable的子接口,ArrayList的父類AbstractList正確地實作了Iterable接口的iterator方法。之前我自己寫的ArrayList用foreach循環直接報空指標異常是因為我自己寫的ArrayList並沒有實作Iterable介面

#

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中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!