簡介
一般來說,我們建立類和接口的時候都是一個類一個檔案,一個接口一個檔案,但有時候為了友善或者某些特殊的原因,java并不介意在一個檔案中寫多個類和多個接口,這就有了我們今天要講的内部類和内部接口。
内部類
先講内部類,内部類就是在類中定義的類。類中的類可以看做是類的一個屬性,一個屬性可以是static也可以是非static的。而内部類也可以定義在類的方法中,再加上匿名類,總共有5種内部類。
靜态内部類
我們在class内部定義一個static的class,如下所示:
@Slf4jpublic class StaticInnerClass { static class Inner { void print() { log.info("Inner class is: " + this); } } public static void main(String[] args) { StaticInnerClass.Inner inner = new StaticInnerClass.Inner(); inner.print(); }}
因為static變量可以直接根據類名來存取,是以我們使用new StaticInnerClass.Inner()來執行個體化内部類。
非靜态内部類
class中定義的類也可以是非靜态的,如下所示:
@Slf4jpublic class InnerClass { class Inner { void print() { log.info("Inner class is: " + this); } } public static void main(String[] args) { InnerClass.Inner inner = new InnerClass().new Inner(); inner.print(); }}
要通路到類的變量,需要執行個體化外部内,然後再執行個體化内部類:new InnerClass().new Inner()。
注意這裡我們需要使用到兩個new。
靜态方法内部類
我們可以在靜态方法中定義一個類,這個類其實就相當于方法中的變量,這個變量當然不能是static的。我們看下面的例子:
@Slf4jpublic class StaticMethodInnerClass { private static String x = "static x"; public static void print() { class MyInner { public void printOuter() { log.info("x is " + x); } } MyInner i = new MyInner(); i.printOuter(); } public static void main(String[] args) { StaticMethodInnerClass.print(); }}
方法中的類,我們是無法在外部執行個體化的。
非靜态方法的内部類
同樣的非靜态方法也可以定義内部類:
@Slf4jpublic class MethodInnerClass { private String x = "non static x"; public void print() { class MyInner { public void printOuter() { log.info("x is " + x); } } MyInner i = new MyInner(); i.printOuter(); } public static void main(String[] args) { new MethodInnerClass().print(); }}
注意,這裡需要先執行個體化外部類才可以繼續調用。
匿名類
最後一個,匿名類,直接在需要的時候執行個體化的類。匿名類我們遇到了很多次了,比如在建構SortedSet的時候,可以傳入自定義的Comparator,我們可以用匿名類來實作,也可以直接使用lambda表達式。
public class AnonymousClass { public static void main(String[] args) { SortedSet sortedSet1 = new ConcurrentSkipListSet(new Comparator(){ @Override public int compare(Object o1, Object o2) { return 0; } }); SortedSet sortedSet2 = new ConcurrentSkipListSet((o1, o2) -> 0); }}
内部接口
Inner Interface是指在接口中定義的接口。最常見的就是Map中的Entry了:
public interface Map { interface Entry { K getKey(); }
這裡的内部接口一定是static的,因為接口是不能執行個體化的,是以為了通路到接口中的接口,必須定義為static。如果不指定,則預設就是static。
我們看一個該内部接口的實作:
public class MapImpl implements Map.Entry{ @Override public Object getKey() { return 0; } @Override public Object getValue() { return null; } @Override public Object setValue(Object value) { return null; }}
總結
本文講解了5個内部類的實作和一個内部接口的應用。大家隻要把内部的類或者接口看成一個變量,就可以很好的了解上面的内容了。
本文作者:flydean程式那些事
本文來源:flydean的部落格
歡迎關注我的公衆号:程式那些事,更多精彩等着您!