【Java程式設計思想】(6)內部類
1. 建立內部類
更典型的情況是,外部類將有一個方法,該方法返回一個指向內部類的引用。
如果想從外部類的非靜態方法之外的任意位置建立某個內部類的物件,那麼必須具體地指明這個物件的型別:OuterClassName.InnerClassName。public class Parcel2 { class Contents { private int i = 11; public int value() { return i; } } class Destination { private String label; Destination(String whereTo) { label = whereTo; } String readLabel() { return label; } } public Destination to(String s) { return new Destination(s); } public Contents contents() { return new Contents(); } public void ship(String dest) { Contents c = contents(); Destination d = to(dest); System.out.println(d.readLabel()); } public static void main(String[] args) { Parcel2 p = new Parcel2(); p.ship("Tasmania"); Parcel2 q = new Parcel2(); // Defining references to inner classes: Parcel2.Contents c = q.contents(); Parcel2.Destination d = q.to("Borneo"); } }
2. 連結到外部類
當生成一個內部類的物件時,此物件與製造它的外圍物件(enclosing object)之間就有了一種聯絡,所以它能訪問其外圍物件的所有成員,而不需要任何特殊條件。此外,內部類還擁有其外圍類的所有元素的訪問權。
當某個外圍類的物件建立了一個內部類物件時,此內部類物件必定會祕密的捕獲一個指向那個外圍類物件的引用。然後,在你訪問此外圍類的成員時,就是用那個引用來選擇外圍類的成員。interface Selector { boolean end(); Object current(); void next(); } public class Sequence { private Object[] items; private int next = 0; public Sequence(int size) { items = new Object[size]; } public void add(Object x) { if (next < items.length) { items[next++] = x; } } private class SequenceSelector implements Selector { private int i = 0; public boolean end() { return i == items.length; } public Object current() { return items[i]; } public void next() { if (i < items.length) { i++; } } } public Selector selector() { return new SequenceSelector(); } public static void main(String[] args) { Sequence sequence = new Sequence(10); for (int i = 0; i < 10; i++) { sequence.add(Integer.toString(i)); } Selector selector = sequence.selector(); while (!selector.end()) { System.out.println(selector.current() + " "); selector.next(); } } }
3. 使用this與new
如果你需要生成對外部類物件的引用,可以使用外部類的名字後面緊跟圓點和this。這樣產生的引用自動地具有正確的型別,這一點在編譯期就被知曉並受到檢查,因此沒有任何執行時開銷。有時你可能想要告知某些其他物件,去建立其某個內部類的物件。要實現此目的,你必須在new表示式中提供對其他外部類物件的引用,這時需要使用.new語法,例如:
public class DotNew { public class Inner{} public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner(); } }
要想直接建立內部類的物件,你不能按照你想象的方式,去引用外部類的名字DotNew,而是必須使用外部類的物件來建立該內部類物件。這也解決了內部類名字作用域的問題,因此你不必宣告(實際上你不能宣告)dn.new DotNew.Inner()。
在擁有外部類物件之前是不可能建立內部類物件的。這是因為內部類物件會暗暗的連結到建立它的外部類物件上。但是,如果你建立的是巢狀類(靜態內部類),那麼它就不需要對外部類物件的引用。
4. 內部類與向上轉型
當將內部類向上轉型為其基類,尤其是轉型為一個介面的時候,內部類就有了用武之地。(從實現了某個介面的物件,得到對此介面的引用,與向上轉型為這個物件的基類,實質上效果是一樣的。)這是因為此內部類——某個介面的實現——能夠完全不可見,並且不可用。所得到的只是指向基類或介面的引用,所以能夠很方便地隱藏實現細節。
5. 在方法和作用域內的內部類
可以在一個方法裡面或者在任意的作用域內定義內部類,這麼做有兩個理由:
(1). 實現了某型別的介面,於是可以建立並返回對其的引用。
(2). 解決一個複雜的問題,想建立一個類來輔助你的解決方案,但是又不希望這個類是公共可用的。
內部類的使用情況:
(1). 定義在方法中的類
public class Parcel5 {
public Destination destination(String s) {
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel5 p = new Parcel5();
Destination d = p.destination("Tasmania");
}
}
(2). 定義在作用域內的類,此作用域在方法的內部。
public class Parcel6 {
private void internalTracking(boolean b) {
if (b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() {
return id;
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
// Can't use it here! Out of scope:
// ! TrackingSlip ts = new TrackingSlip("x");
}
}
public void track() {
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 p = new Parcel6();
p.track();
}
}
(3). 實現了介面的匿名類。
public class Parcel7 {
public Contents contents() {
return new Contents() {
private int i = 11;
public int value() {
return i;
}
};
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
(4). 匿名類,它擴充套件了有非預設構造器的類
public class Parcel8 {
public Wrapping wrapping(int x) {
// Base constructor call:
return new Wrapping(x) { // pass constructor arguments
public int value() {
return super.value() * 47;
}
}; // Semicolon required
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);
}
}
(5). 匿名類,它執行欄位初始化。
public class Parcel9 {
public Destination destination(final String dest) {
return new Destination() {
private String label = dest;
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
(6). 匿名類,它通過例項初始化實現構造(匿名類不可能有構造器)。
abstract class Base {
public Base(int i) {
System.out.println("Base constructor. i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i ) {
return new Base(i) {
{
System.out.println("Inside instance initializer");
}
public void f() {
System.out.println("In anomymous f()");
}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
傳遞到匿名內部類中並使用的引數必須是final的。
匿名內部類與正規的繼承相比有些受限,因為匿名內部類既可以擴充套件類,也可以實現介面,但是不能兩者兼備。而且如果是實現介面,也只能實現一個介面。
優先使用類而不是介面。如果你的設計中需要某個介面,你必須瞭解它。否則,不到迫不得已,不要將其放到你的設計中。
6. 巢狀類
如果不需要內部類物件與其外圍類物件之間有聯絡,那麼可以將內部類宣告為static。這通常被稱為巢狀類。想要理解static應用於內部類時的含義,就必須記住,普通的內部類物件隱式地儲存了一個引用,指向建立它的外圍類物件。然而,當內部類是static的時,就不是這樣了。巢狀類意味著:
(1). 要建立巢狀類的物件,並不需要其外圍類的物件。
(2). 不能從巢狀類的物件中訪問非靜態的外圍類物件。
巢狀類與普通的內部類還有一個區別。普通內部類的欄位與方法,只能放在類的外部層次上,所以普通的內部類不能有static資料和static欄位,也不能包含巢狀類。但是巢狀類可以包含所有這些東西。
在一個普通的(非static)內部類中,通過一個特殊的this引用可以連結到其外圍類物件。巢狀類就沒有這個特殊的this引用,這使得它類似於一個static方法。
7. 介面內部的類
正常情況下,不能在介面內部放置任何程式碼,但巢狀類可以作為介面的一部分。你放到介面中的任何類都自動地是public和static的。因為類是static的,只是將巢狀類置於介面的名稱空間內,這並不違反介面的規則。你甚至可以在內部類中實現其外圍介面。
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface {
public void howdy() {
System.out.println("Howdy!");
}
public static void main(String[] args) {
new Test().howdy();
}
}
}
如果你想要建立某些公共程式碼,使得它們可以被某個介面的所有不同實現所共用,那麼使用介面內部的巢狀類會顯得很方便。
一個內部類被巢狀多少層並不重要——它能透明的訪問所有它所嵌入的外圍類的所有成員:
class MNA {
private void f() {
}
class A {
private void g() {
}
public class B {
void h() {
g();
f();
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args) {
MNA mna = new MNA();
MNA.A mnaa = mna.new A();
MNA.A.B mnaab = mnaa.new B();
mnaab.h();
}
}
可以看到在MNA.A.B中,呼叫方法g()和f()不需要任何條件(及時它們被定義為private)。這個例子同時展示瞭如何從不同的類裡建立多層巢狀的內部類物件的基本語法。”.new“語法能產生正確的作用域,所以不必在呼叫構造器時限定類名。
8. 為什麼需要內部類
一般來說,內部類繼承自某個類或實現某個介面,內部類的程式碼操作建立它的外圍類的物件。所以可以認為內部類提供了某種進入其外圍類的視窗。
內部類必須要回答的一個問題是:如果只是需要一個對介面的引用,為什麼不通過外圍類實現按個介面呢?答案是:”如果這能買足需求,那麼就應該這樣做。”那麼內部類實現一個介面與外圍類實現這個介面有什麼區別呢?答案是:後者不是總能享用到介面帶來的方便,有時需要用到介面的實現。所以,使用內部類最吸引人的原因是:
每個內部類都能獨自地繼承自一個(介面的)實現,所以無論外圍類是否已經繼承了某個(介面的)實現,對於內部類都沒有影響。
如果沒有內部類提供的、可以繼承多個具體的或抽象的類的能力,一些設計與程式設計問題就很難解決。從這個角度看,內部類使得多重繼承的解決方案變的完整。介面解決了部分問題,而內部類有效地實現了“多重繼承”。也就是說,內部類允許繼承多個非介面型別(譯註:類或抽象類)。
如果不需要解決“多重繼承”的問題,那麼自然可以用別的方式編碼,而不需要使用內部類。單如果使用內部類,還可以獲得其他一些特性:
(1). 內部類可以有多個例項,每個例項都有自己的狀態資訊,並且與其外圍類物件的資訊相互獨立。
(2). 在單個外圍類中,可以讓多個內部類以不同的方式實現同一個介面,或繼承同一個類。
(3). 建立內部類物件的時刻並不依賴於外圍類物件的建立
(4). 內部類並沒有令人迷惑的"is-a"關係;它就是一個獨立的實體。
9. 閉包與回撥
閉包(closure)是一個可呼叫的物件,它記錄了一些資訊,這些資訊來自於建立它的作用域。通過這個定義,可以看出內部類是面相物件的閉包,因為它不僅包含外圍類物件(建立內部類的作用域)的資訊,還自動擁有一個指向此外圍類物件的引用,在此作用域內,內部類有權操作所有的成員,包括private成員。 Java最引人爭議的問題之一就是,人們認為Java應該包含某種類似指標的機制,以允許回到(callback)。通過回撥,物件能夠攜帶一些資訊,這些資訊允許它在稍後的某個時刻呼叫初始的物件。如果回撥是通過指標實現的,那麼就只能寄希望於程式設計師不會誤用該指標。然而,Java更小心仔細,所以沒有在語言中包括指標。 通過內部類提供閉包功能是優良的解決方案,它比指標更靈活、更安全:interface Incrementable {
void increment();
}
// very simple to just implement the interface:
class Callee1 implements Incrementable {
private int i = 0;
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement {
public void increment() {
System.out.println("Other operation");
}
static void f(MyIncrement mi) {
mi.increment();
}
}
// If your class must implement increment() in some other way, you must use an
// inner class:
class Callee2 extends MyIncrement {
private int i = 0;
public void increment() {
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
public void increment() {
// Specify outer-class method, otherwise you'd get an infinite
// recursion:
Callee2.this.increment();
}
}
Incrementable getCalIncrementable() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) {
callbackReference = cbh;
}
void go() {
callbackReference.increment();
}
}
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCalIncrementable());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
回撥的價值在於它的靈活性——可以執行時動態的決定需要呼叫什麼方法。
10. 內部類與控制框架
應用程式框架(application framework)就是被設計用以解決某類特定問題的一個類或一組類。要運用某個應用程式框架,通常是繼承一個或多個類,並覆蓋某些方法。在覆蓋後的方法中,編寫程式碼定製應用程式框架提供的通用解決方案,以解決特定問題(這是設計模式中模板方法的一個例子)。模板方法包含演算法的基本結構,並且會呼叫一個或多個可覆蓋的方法,以完成演算法的動作。設計模式總是將變化的事物與保持不變的事物分開,在這個模式中,模板方法是保持不變的事物,而可覆蓋的方法就是變化的事物。
控制框架是一類特殊的應用程式框架,它用來解決響應事件的需求。主要用來響應事件的系統被稱作事件驅動系統。應用程式設計中常見的問題之一是圖形使用者介面(GUI),它幾乎完全是事件驅動的系統。
11. 內部類的繼承
class WithInner {
class Inner {
}
}
public class InheritInner extends WithInner.Inner {
public InheritInner(WithInner wi) {
wi.super();
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}
可以看到,InheritInner只繼承自內部類,而不是外圍類。但是當要生成一個構造器時,預設的構造器並不算好,而且不能只是傳遞一個指向外圍類物件的引用。此外,必須在構造器內使用如下語法:
enclosingClassReference.super();
這樣才提供了必要的引用,然後程式才能編譯通過。
12. 內部類可以被覆蓋嗎
class Egg {
private Yolk y;
protected class Yolk {
public Yolk() {
System.out.print("Egg.Yolk()");
}
}
public Egg() {
System.out.print("New Egg()");
y = new Yolk();
}
}
public class BigEgg {
public class Yolk {
public Yolk() {
System.out.print("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
預設的構造器是編譯器自動生成的,這裡是呼叫基類的預設構造器。你可能認為既然建立了BigEgg的物件,那麼所使用的應該是“覆蓋後”的Yolk版本,但從輸出中可以看到實際情況並不是這樣的。
這個例子說明,當繼承了某個外圍類的時候,內部類並沒有發生什麼特別神奇的變化。這兩個內部類是完全獨立的兩個實體,各自在自己的名稱空間內。
明確的繼承某個內部類也是可以的:
class Egg2 {
protected class Yolk {
public Yolk() {
System.out.println("Egg2.Yolk()");
}
public void f() {
System.out.println("Egg2.Yolk.f()");
}
}
private Yolk y = new Yolk();
public Egg2() {
System.out.println("New Egg2()");
}
public void insertYolk(Yolk yy) {
y = yy;
}
public void g() {
y.f();
}
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.Yolk {
public Yolk() {
System.out.println("BigEgg2.Yolk()");
}
public void f() {
System.out.println("BigEgg2.Yolk.f()");
}
}
public BigEgg2() {
insertYolk(new Yolk());
}
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
}
現在BigEgg2.Yolk通過extends Egg2.Yolk明確地繼承了此內部類,並且覆蓋了其中的方法。insertYolk()方法允許BigEgg2將它自己的Yolk物件向上轉型為Egg2中的引用y。所以當g()呼叫y.f()時,覆蓋後的新版的f()被執行。第二次呼叫Egg2.Yolk(),結果是BigEgg2.Yolk的構造器呼叫了其基類的構造器。可以看到在呼叫g()的時候,新版的f()被呼叫了。13. 區域性內部類
可以在程式碼塊裡建立內部類,典型的方式是在一個方法體的裡面建立。區域性內部類不能有訪問說明符,因為它不是外圍類的一部分;但是可以訪問當前程式碼塊內的常量,以及此外圍類的所有成員。
interface Counter {
int next();
}
public class LocalInnerClass {
private int count = 0;
Counter getCounter(final String name) {
// A local inner class:
class LocalCounter implements Counter {
public LocalCounter() {
System.out.println("LocalCounter()");
}
public int next() {
System.out.println(name);
return count++;
}
}
return new LocalCounter();
}
// The same thing with an anonymous inner class:
Counter getCounter2(final String name) {
return new Counter() {
{
System.out.println("Counter()");
}
public int next() {
System.out.println(name);
return count++;
}
};
}
public static void main(String[] args) {
LocalInnerClass lic = new LocalInnerClass();
Counter c1 = lic.getCounter("Local inner"), c2 = lic
.getCounter2("Anomymous inner");
for (int i = 0; i < 5; i++) {
System.out.println(c1.next());
}
for (int i = 0; i < 5; i++) {
System.out.println(c2.next());
}
}
}
Counter返回的是序列中的下一個值。我們分別使用區域性內部類和匿名內部類實現了這個功能,它們具有相同的行為和能力。既然區域性內部類的名字在方法外是不可見的,那為什麼我們讓然使用區域性內部類而不是匿名內部類呢?唯一的理由是,我們需要一個已命名的構造器,或者需要過載構造器,而匿名內部類只能用於例項初始化。
所以使用區域性內部類而不是用匿名內部類的另一個理由就是,需要不止一個該內部類的物件。
14. 內部類識別符號
內部類在編譯的時候也會產生一個.class檔案以包含它們的class物件資訊。這些類檔案的命名有嚴格的規則:外圍類的名字,加上"$",再加上內部類的名字。 如果內部類是匿名的,編譯器會簡單的產生一個數字作為其識別符號。如果內部類是巢狀在別的內部類之中,只需直接將它們的名字加在其外圍類識別符號與"$"的後面。相關推薦
【Java程式設計思想】(6)內部類
1. 建立內部類 更典型的情況是,外部類將有一個方法,該方法返回一個指向內部類的引用。 public class Parcel2 { class Contents { private int i = 11; public int value() { ret
【Java程式設計思想】10.內部類
將一個類的定義放在另一個類的定義內部,這就是內部類。 10.1 建立內部類 內部類的名字是巢狀在外部類裡面的 外部類可以有方法,返回一個指向內部類的呼叫。(外部類中可以呼叫內部類) 如果在外部類中,希望能在除了靜態方法之外的任意位置建立某個內部類物件,那麼可以向下面這樣指明物件型別。
【Java程式設計思想】12.通過異常處理錯誤
Java 的基本理念是“結構不佳的程式碼不能執行”。 異常處理是 Java 中唯一正式的錯誤報告機制,並且通過編譯器強制執行。 12.1 概念 異常機制會保證能夠捕獲錯誤,並且只需在一個地方(即異常處理程式中)處理錯即可。 12.2 基本異常 異常情形(exceptional conditio
【Java程式設計思想】11.持有物件
如果一個程式只包含固定數量的且生命週期都是已知的物件,那麼這是一個非常簡單的程式。 Java 類庫中提供一套容器類,來儲存比較複雜的一組物件。其中有 List、Set、Queue、Map 等。這些類也被稱為集合類,Java 的類庫中使用 Collection 這個名字指代該類庫的一個特殊子集(其實 Java
【Java程式設計思想】9.介面
介面和內部類為我們提供了一種將介面與實現分離的更加結構化的方法。 9.1 抽象類和抽象方法 Java 提供抽象方法機制,這種方法時不完整的,僅有宣告,沒有方法體。 包含抽象方法的類叫做抽象類。如果一個類包含一個或多個抽象方法,那麼該類必須被限定為是抽象的(否則編譯器報錯)。 一個抽象類不完整的時候,
【Java程式設計思想】8.多型
在面向物件的程式設計語言中,多型是繼資料抽象和繼承之後的第三種基本特徵。 多型分離了“做什麼”和“怎麼做”,讓介面和實現分離開,改善了程式碼的可讀性和組織結構,建立了可拓展的程式。 封裝,通過合併特徵和行為來建立新的資料型別。 實現隱藏,通過將細節“私有化”把介面和實現分離開來。 多型,消除型
【Java程式設計思想】13.字串
字串操作是計算機程式設計中最常見的行為。 13.1 不可變 String String 物件是不可變的。String 類中每一個看起來會修改 String 值的方法,實際上都是建立了一個全新的 String 物件去包含修改後的字串內容;而最初的 String 物件則沒有改變。 每當吧 Stirng 物
【Java程式設計思想】5.初始化與清理
構造器就是在建立物件的時候被自動呼叫的特殊方法。 Java 在提供構造器的基礎上,額外提供“垃圾回收器”。控制物件從生命週期開始到結束。 5.1 用構造器確保初始化 建立物件時,Java 會在使用者有能力操作物件之前自動呼叫構造器,保證初始化進行。 5.2
【Java程式設計思想】讀書筆記(一)第一章---第五章
Java程式設計思想(第四版)學習筆記 第一章---第五章 第一章:物件導論 1.1抽象過程 1. 2訪問控制 第二章:一切都是物件 2. 1用引用操縱物件 2. 2基本型別 第三章:操作符
【Java程式設計思想】第四版課後習題筆記
2.11練習10: 編寫一個程式:打印出從命令列獲得的三個引數。為此,需要確定命令列陣列中string的下標。 書上的答案是: public class E10 { public static void main(String[] args) { System.out.prin
工廠方法模板(java程式設計思想 使用匿名內部類)
package innerclasses; interface Service{ void method1(); void method2(); } interface ServiceFactory{ Service getService(); } class
【Java程式設計思想】14.型別資訊
執行時型別資訊使得你可以在程式執行時發現和使用型別資訊。 Java 中在執行時識別物件和類的資訊的方式有兩種: “傳統的” RTTI,它假定在編譯時我們就已經知道所有型別。 反射機制,允許我們在執行時發現和使用類的資訊。 14.1 為什麼需要 RTTI
【Java編程思想】10.內部類
hang work return you 非靜態內部類 for each del 覆蓋 類文件 將一個類的定義放在另一個類的定義內部,這就是內部類。 10.1 創建內部類 內部類的名字是嵌套在外部類裏面的 外部類可以有方法,返回一個指向內部類的調用。(外部類中可以調用內
快樂程式設計大本營【java語言訓練班】 6課:用java的物件和類程式設計
快樂程式設計大本營【java語言訓練班】 6課:用java的物件和類程式設計 第1節. 什麼是物件和類 第2節. 物件的屬性和方法 第3節. 類的繼承 第4節. 使用舉例:建立類,定義方法,定義屬性 第5節. 使用舉例:建立物件,屬性賦值與使用,方法呼叫; 第6節. 使用舉例:類繼承及物件使用 地址如下
【Java程式設計思想筆記】第六章-訪問許可權控制
要學會把變動的程式碼與保持不變的程式碼區分開來。 如果有必要,你儘可能將一切方法都定為private。 非public類在其它包中是訪問不到的。 所有預設包的類都是屬於同一個包,儘管它們在不同的資料夾下面。 private,只允許本類所有物件可訪問,其他任何類
【Java程式設計思想筆記】第四章-流程控制
Foreach迴圈可用於陣列,以及實現了java.util.Iterator介面的物件。 public interface Iterable<T> { Iterator<T> iterator(); } 如果在返回v
【Java程式設計思想閱讀筆記】Java資料儲存位置
Java資料儲存位置 P46頁有感 一、前置知識 棧是由系統自動分配的,Java程式設計師對棧沒有直接的操作許可權, 堆是所有執行緒共享的記憶體區域,棧 是每個執行緒獨享的。 堆是由程式設計師自己申請的,在使用new關鍵字建立一個物件的時候,物件就會被分配到堆記憶體中。並且由於棧是由系統自動分配的,因此申請
Java程式設計思想(6)
第19章 列舉型別 1 enum的函式,ordinal()返回enum的int值,name()返回enum的值 enum Shrubbery {GROUND,CRAWLING,HANGING} public class TwoTuple{ public static void mai
函式式介面@FunctionalInterface學習(函式程式設計思想)------------與匿名內部類對比
在java8中 1、新推出了一個介面概念:函式式介面。 2、允許介面也可以有default方法,default方法可以方法體。 他滿足以下規範: 介面有且只能有個一個抽象方法(抽象方法只有方法定義,沒有方法體) 不能在介面中覆寫Object類中的publi
【單例深思】靜態內部類實現詳解
靜態內部類實現是我個人比較推薦的,其實現如下: publicclass Singleton { private static class SingletonHolder {