第二十二條 優先考慮靜態成員類
java中巢狀類有四種,現在舉例說明: 靜態成員類 非靜態成員類 區域性類 匿名類 。
class Outer {
int age = 20; String name = "outer";
static class Inner { int age = 10; String name = "inner";
} } 靜態內部類, 呼叫方法 Outer.Inner inner = new Outer.Inner(); 生成一個內部類的物件
class Outer {
int age = 20; String name = "outer";
class Inner { int age = 10; String name = "inner";
} } 非靜態內部類, 呼叫方法 Outer.Inner inner = new Outer().new Inner(); 生成物件,注意與上面的靜態類的生成方法有何不同
class Outer {
int age = 20; String name = "outer";
public void test(){ class Inner{ int age = 20; String name = "outer";
public void testPrint(){ System.out.println(" age " + age + " name " + name); } } Inner inner = new Inner(); inner.testPrint(); } } 區域性類,呼叫方法 Outer outer = new Outer(); outer.test(); 區域性類範圍更小,更像是區域性的輔助類
class Outer {
int age = 20; String name = "outer";
public void test(){ System.out.println(" age " + age + " name " + name); } } 匿名類, 呼叫方法 new Outer().test();
匿名類我們平常可能經常用到,不如給一個方法傳遞一個物件,可以直接new一個,好處就是用完就回收,比較節省記憶體,這種常用帶一次呼叫的場景;區域性類這種方法,平時用到的不多,算是小範圍的輔助類,一般都是定義在方法裡,用完就完了;
靜態成員類 和 非靜態成員類 這兩種用的比較多,重點說一下。靜態成員類可以理解為是一個單獨的類,只是恰好定義在一個類的內部而已,僅此而已。它不會對它外部的類持有物件引用而消耗大量記憶體或者造成記憶體洩漏。這種類一般都是作為輔助類,和外部類一起用才有意義。比如常見的 Builder 模式、 列舉 等等。 非靜態成員類比著靜態的少了個 static 的修飾,但會發現,建立物件的方法不一樣, Outer.Inner inner = new Outer.Inner(); Outer.Inner inner = new Outer().new Inner(); 還是有差別的, 非靜態內部類的例項會對外部類造成引用,會產生關聯關係,當外部類呼叫內部類的方法時,關係就會被建立,這種記憶體的消耗是持續的。 非靜態內部類中不允許出現靜態變數和靜態方法的宣告,static 只能用在常量的宣告上; 靜態內部類則無此現在。
例如, HashMap 中 的
public final Spliterator<V> spliterator() { return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0); }
static final class ValueSpliterator<K,V> extends HashMapSpliterator<K,V> implements Spliterator<V> { ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } }
static class HashMapSpliterator<K,V> { final HashMap<K,V> map; HashMapEntry<K,V> current; // current entry int index; // current index, modified on advance/split int fence; // one past last index int est; // size estimate int expectedModCount; // for comodification checks
HashMapSpliterator(HashMap<K,V> m, int origin, int fence, int est, int expectedModCount) { this.map = m; this.index = origin; this.fence = fence; this.est = est; this.expectedModCount = expectedModCount; } }
建立 迭代器時,迭代器內部要對Map的 HashMapEntry,HashMapEntry 繼承 Map.Entry, 即會產生大量的 Entry 物件,如果以上沒有static 的修飾,會造成每個entry都包含一個map的引用,造成極大的空間和時間的浪費。
平常如果用內部類,更多的是是靜態的,基本無記憶體洩漏的危險。靜態和非靜態各有好處,如果拿不準用哪個,那就選 靜態 的吧。