for-each 與引用類型、參數傳遞組合考點

for-each 與引用類型、參數傳遞組合考點

  • for-each loop
    • for-each loop traverse array
    • for-each 循環的等價代碼
    • 原始類型值的複製
  • 自定義類對象作為參數傳遞
    • 自定義 toString 方法
    • 普通 for 循環遍曆對象數組
    • 對象的別名 alias name
    • for-each 與保存原始類型的數組
    • 對象數組與 for-each 循環
    • 等效代碼
  • ArrayList 使用 for-each 的行為和 array 相同

for-each loop

for-each loop traverse array

當我們(men) 想要訪問數組或者列表中的每一個(ge) 元素,但是又不關(guan) 心索引的時候,適合使用 for-each 循環。

int[] hs = {12345}; for(int element : hs) {     System.out.println(element); }

1
2
3
4
5

for-each 循環的等價(jia) 代碼

對於(yu) 原始類型的數組,利用 for-each loop 無法改變元素的值。

int[] hs = {12345}; // for-each loop 相當於(yu) 下麵的代碼 // int element = hs[0]; // 把 hs[0] 的副本賦值給 element // // do something // element 的變化,不影響 hs[0] // elment = hs[1]; // // do something // elment = hs[2]; // // do something // elment = hs[3]; // // do something // elment = hs[4]; // // do something for(int element : hs) {     element = 0// 試圖把所有元素都變成 0 } for(int element : hs) {     System.out.println(element); } // 輸出的內(nei) 容還是數組原來的內(nei) 容

1
2
3
4
5

但是結果沒有變成 0,這是因為(wei) ,hs 是一個(ge) 整數類型的數組,int 是原始類型,賦值是建立一個(ge) 副本,然後再賦值給 element,相當於(yu)  element = hs[0], element = hs[1],但是因為(wei) 是整數,所以 element 中保存的是 hs[0] 中的數值的副本,所以修改 element 不能修改索引為(wei) 0 的值,或者不能修改數組對應的值。

原始類型值的複製

需要注意的是,參數傳(chuan) 遞的過程就是把實際參數的值賦值給形式參數的過程。原始類型的複製是創建副本 copy 然後傳(chuan) 遞給形式參數;引用類型(指向對象的變量)裏麵保存的是地址,所以引用類型實際參數賦值給形式參數把對象的地址複製了一份傳(chuan) 遞給形式參數,這就是為(wei) 什麽(me) 說對象傳(chuan) 遞的是索引。

for-each 會(hui) 依次把數組中的元素賦值給 element 循環變量,但是這個(ge) 賦值是創建了副本的,element 的變化不影響數組中原來的值。

int a = 2; int b = a; // b 中保存的是 a 的副本,原始類型賦值會(hui) 創建副本 // b 的變化不影響 a b = 10; System.out.println(a); // a 的值仍然是 2

2

這個(ge) 結論,對於(yu) 任意的原始類型的數組,都是成立的。

自定義類對象作為參數傳遞

class Student {     private String name;     public Student(String n)     {         name = n;     }     // accessor     public void setName(String n) {name = n;}     // mutator     public String getName() return name;} }

數組中除了原始類型,還可以保存引用類型reference type,或者說可以保存對象。

Student[] guys = {new Student("lucy"),      new Student("lily"),      new Student("tom")};

for (Student stu : guys)
{
   System.out.println(stu); // 輸出的是默認 toString 的結果 }

下麵輸出的是 jupyter notebook 環境中,對象 toString 方法的默認的實現,我們(men) 可以自定義(yi) toSring 方法,自行定義(yi) 對象的字符串表示形式。

REPL.$JShell$16C$Student@4af3eec1 REPL.$JShell$16C$Student@537aa7fe REPL.$JShell$16C$Student@60221fa7

class Student {
    private String name;
    public Student(String n)     {
        name = n;
    }
    public void setName(String n) {name = n;}
    public String getName() return name;}
    public String toString() {return "[Student: " + name + "]";}
}

自定義(yi) toString 方法

我們(men) 定義(yi) 了自己的版本的 toString 然後我們(men) 在看打印的效果:

Student[] guys = {new Student("lucy"), new Student("lily"), new Student("tom")}; for (Student stu : guys) {    System.out.println(stu); // 輸出的是默認 toString 的結果 }

[Student: lucy]
[Student: lily]
[Student: tom]

普通 for 循環遍曆對象數組

我們(men) 發現,對於(yu) 對象數組,我們(men) 仍然可以方便的使用 for-each 循環麽(me) ,我們(men) 看下用普通 for 循環達到相同效果:

Student[] guys = {new Student("lucy"), new Student("lily"), new Student("tom")}; for (int i = 0; i < guys.length; i++) {    System.out.println(guys[i]); // 輸出的是默認 toString 的結果 }

[Student: lucy]
[Student: lily]
[Student: tom]

如果是要訪問方法就更麻煩。

Student[] guys = {new Student("lucy"), new Student("lily"), new Student("tom")}; for (int i = 0; i < guys.length; i++) {    System.out.println(guys[i].getName()); // 輸出的是默認 toString 的結果 }

對象的別名 alias name

我們(men) 知道,對於(yu) 對象來說,變量其實是指向對象在內(nei) 存的地址,所以我們(men) 也可以把這些變量叫做對象的引用。
比如說:Student guy = new Student("zhangsan");,guy 其實就是對 Student 對象的引用,guy 引用的那個(ge) 對象的名字是 zhangsan。如果我們(men) 執行這樣代碼:Student s = guy 那麽(me) 我們(men) 知道,guy 中地址,創建一個(ge) 副本,然後賦值給 s,所以引用類型其實傳(chuan) 遞的是對象在內(nei) 存中的地址。

Student guy = new Student("zhangsan"); Student s = guy; // s is alias name of guy object // guy 和 s 中保存了對象在內(nei) 存的地址,是一個(ge) 對對象的引用

如果我在 s 上調用方法,同時會(hui) 修改 guy 指向的對象:

s.setName("laohuang"); System.out.println(guy.getName());

laohuang

我們(men) 雖然沒有在 guy 上調用 name 屬性的修改器,但是 s 和 guy 其實指向的是同一個(ge) 對象,所以 s 上調用方法,和在 guy 上調用方法是等效的。

guy.setName("lisi");System.out.println(s.getName());

lisi

for-each 與(yu) 保存原始類型的數組

對於(yu) 原始類型來說,我們(men) 無法通過 for-each 循環來修改數組中的元素:

int[] hs = {12345}; for(int element : hs) {     element = 0// 試圖把所有元素都變成 0 } for(int element : hs) {     System.out.println(element); }

1
2
3
4
5

對象數組與(yu) for-each 循環

但是,對於(yu) 對象數組來說,利用 for-each 循環,通過循環變量是可以修改數組中元素的屬性的,舉(ju) 例如下:

Student[] guys = {new Student("lucy"),                    new Student("lily"),                    new Student("tom")}; for (Student stu : guys) {    stu.setName("lisi"); // stu 其實依次是每個(ge) 元素的別名,所以可以修改屬性 } for (Student stu : guys) {    System.out.println(stu); // 輸出的是默認 toString 的結果 }

[Student: lisi]
[Student: lisi]
[Student: lisi]

等效代碼

對於(yu) for-each 循環來說,相當於(yu) 下麵的代碼:

Student[] guys = {new Student("lucy"), new Student("lily"), new Student("tom")}; for (Student stu : guys) {    System.out.println(stu); // 輸出的是默認 toString 的結果 } Student stu = guys[0]; // stu 實際上 new Student("lucy") 的別名 alias name stu.setName("lisi"); stu = guys[1]; stu.setName("lisi"); stu = guys[2]; stu.setName("lisi"); for (Student stu : guys) {    System.out.println(stu); // 輸出的是默認 toString 的結果 }

[Student: lucy]
[Student: lily]
[Student: tom]
[Student: lisi]
[Student: lisi]
[Student: lisi]

ArrayList 使用 for-each 的行為(wei) 和 array 相同

對於(yu) 對象來說,無論是 array 還是 ArrayList,利用 for-each 的循環變量,都是可以修改數組或者列表中的元素的。

ArrayList<Student> guys = new ArrayList<>();guys.add(new Student("zhangsan")); guys.add(new Student("lucy")); guys.add(new Student("wangwu")); for (Student stu : guys) // stu 是引用類型,賦值傳(chuan) 遞的是引用,而非副本 {    stu.setName("lisi"); // stu 其實依次是每個(ge) 元素的別名,所以可以修改屬性 } for (Student stu : guys) {    System.out.println(stu); // 輸出的是默認 toString 的結果 }

[Student: lisi]
[Student: lisi]
[Student: lisi]

可以看到,利用循環變量 stu 依次調用方法,可以修改列表對象的屬性;這是因為(wei) ,對於(yu) 對象來說,引用的賦值創建的地址的副本,stu 依次是列表中每個(ge) 元素別名,從(cong) 而使得這個(ge) 時候可以修改元素。

for-each 與(yu) 引用類型、參數傳(chuan) 遞組合考點

for-each 與(yu) 引用類型、參數傳(chuan) 遞組合考點

for-each 與(yu) 引用類型、參數傳(chuan) 遞組合考點

for-each 與(yu) 引用類型、參數傳(chuan) 遞組合考點

for-each 與(yu) 引用類型、參數傳(chuan) 遞組合考點

歡迎關(guan) 注公眾(zhong) 號。最後添加兩(liang) 個(ge) 關(guan) 於(yu) 嵌套循環 nested loop 講解的視頻,希望對大家有幫助。(應該放數組相關(guan) 的題目的,但是我還沒有錄製,所以上麵放了幾張圖)。

巴朗計算機是一本非常好的教材,事無巨細。但是,缺點也是太詳細了,有些枯燥。學生並不能看到 Java 在實際場景中的應用,所以如果能過結合 processing 或者代碼本色,其實是個(ge) 非常好的選擇。

for-each 與(yu) 引用類型、參數傳(chuan) 遞組合考點

 

這本書(shu) 裏麵的案例都非常的酷炫,適合真正對編程感興(xing) 趣和隊員仿真感興(xing) 趣的學生。

【競賽報名/項目谘詢+微信:mollywei007】

上一篇

國際高中IGCSE課程難度如何?

下一篇

2024年QS排名將更新指標!四大排名究竟參考誰?

你也可能喜歡

  • 暫無相關文章!

評論已經被關(guan) 閉。

插入圖片
返回頂部