iT邦幫忙

0

CMoney工程師戰鬥營weekly3

一山還有一山高課程難度有增無減的一週

上週老師說只要學完抽象類別後應該沒有更難的東西,誰知道!!這週就出現了Lambda:((
在開始說明Lambda之前老師大約花了半小時左右講解了內部類別還有半小時的匿名內部類,正當我開始回顧課程影片時..
當天下午,老師馬上說:嗯~剛剛學的其實不太實用,我們把它全部丟掉吧!
我的臉:(;´༎ຶД༎ຶ`)ಥ_ಥ
然後就滔滔不絕地開始說明Lambda..

內部類別

可以在類別中再定義類別,稱之為內部類別(Inner class)
內部類別通常只為了服務外部類別而存在時。

public class Test {(外)
    public class InnerTest {(內)
        
    }
}
public class Main {
    public static void main(String[] args) {
        Test test = new Test();//創建實體
        Test.InnerTest innerTest = test.new InnerTest();// 需要外部類別實例才能創建內部類別實例
    }
}

Test類別中宣告了另一個類別 InnerTest;InnerTest即為Test的內部類別。
在創建內部類別的實體時我們需要外部類別的實例才能創建內部類別實例,因為內部類別可以使用外部類別當前實例的屬性與方法。

使用內部類別的好處

1.可以直接存取外部類別的私用(privat成員),舉例來說,在視窗程式中,可以使用內部類別來實作一個事件傾聽者類別,這個視窗傾聽者類別可以直接存取視窗元件,而不用透過參數傳遞。
2.當某個slave類別只服務於一個Master類別,我們可將設定為内類別,如此使用Master的人就不知道slave的存在。
存取修飾子的使用:
外部類別只能使用:public、default、final、abstract
內部類別可以使用:private、protected、public、static

靜態內部類

public class Test {
    public static class InnerTest {
    }
}
public class Main {
    public static void main(final String[] args) {
        final Test.InnerTest innerTest = new Test.InnerTest();// 無需依賴外部類別實體便可以被創建
    }
}

內部類別只為了服務外部類別而存在,但有時我們需要在尚未創建外部類別實體時獨立創建內部類別實體。
靜態內部類別不依賴外部類別實體,因此在靜態內部類之中就無法使用外部類別.this來調用屬性(因為不會有外部實體)
當然外部類別之中還是能存取內部類別包含private修飾的所有屬性。

匿名內部類

產生一個匿名(沒有名字)的類別來實現某個介面(或繼承某個抽象類別),因為沒有名字,所以只能建構一次。

public class Main {
    public static void main(final String[] args) {
        int a = 5;
        int b = 3;
        // 使用匿名內部類別創建實現Comparator的類別的實例
        Comparator comparator = new Comparator() {//創建後的實例我們使用Comparator的變數存取
            @Override//覆寫原Comparator方法
            public int compareTo(int a, int b) {
                return a - b;
            }
        };
        System.out.println(comparator.compareTo(a, b));//通過變數調用該實例中的compareTo方法
}

在使用上匿名內部類別在產生出來後會直接創建出該類別的實例,此時可以選擇使用變數存取(動態多型)或直接呼叫對應方法。

Lambda

只能使用於只有一個抽象方法的介面,稱為Functional Interface(函式介面)。
Lambda 語法
//第一種:沒有大括號,可以表達單行程式區塊
(輸入參數,輸入參數,...) -> 單行邏輯程式區塊
//第二種:大括號,可以表達多行程式區塊
(輸入參數,輸入參數,...) -> { ... 多行程式區塊 ...}
*Lambda最需要注意的是傳入的參數對應接口以及執行的內容

String Pool

在Java中,String物件一但建立就無法改變(只能指向新的字串),且在程式之中,String占用記憶體非常大。
因此將String使用物件池方式來管理的收益非常高。
通過字串池(String pool)可以使相同字串得以被重複利用,以進一步達到節省空間的目的。

  • Java程式中比較兩個String變數是否相同時,應該用equals(String s)

String s1 = "hello world";
String s2 = "hello world";

//s1及s2都是直接用雙引號的方式來宣告,JVM在編譯時看到這樣的宣告會去String Pool裡找是否有同樣的字,沒有的話會將字存入String Pool,若有的話則將儲存字的位址返回。
//宣告s1時String Pool裡面沒有任何字,所以JVM會在String Pool的記憶體生一塊位置來存放"hello world",然後將位址返回給s1
宣告s2時,JVM會先拿宣告的"hello world"去String Pool中看是否有存在相同的字,因為s1之前已經宣告過,所以JVM會將s1宣告的"hello world"記憶體位址返回給s2。

String s3 = new String("hello world");

//s3是用new關鍵字產生了一個String Pool外的新的記憶體位置來存放"hello world",與s1及s2的記憶體位址並不相同,所以s1 == s3結果為false。

String s4 = s3.intern();
//intern方法的作用是回傳一個字串在字串池之中的引用。

System.out.println(s1 == s2); // true
//因為兩個字串變數的值實際上都是指向同個記憶體位置的值。
System.out.println(s1 == s3); // false
System.out.println(s3 == s4); // false
System.out.println(s1 == s4); // true
//s4是s3呼叫intern()方法取得的值,該方法是拿s3指向的內容"hello world",去String Pool找是否有相同的內容,若有則回傳String Pool該字的記憶體位址,與s1及s2指向的同一個位址,所以s1 == s4為true。
System.out.println(s1.equals(s3)); // true
System.out.println(s3.equals(s4)); // true


尚未有邦友留言

立即登入留言