thinking-in-java(10)内部类
生活随笔
收集整理的這篇文章主要介紹了
thinking-in-java(10)内部类
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
【0】開(kāi)場(chǎng)白
1)內(nèi)部類(lèi):將一個(gè)類(lèi)的定義放在另一個(gè)類(lèi)的定義內(nèi)部,這個(gè)類(lèi)就是內(nèi)部類(lèi);
2)內(nèi)部類(lèi)優(yōu)點(diǎn):匿名內(nèi)部類(lèi)的一個(gè)優(yōu)點(diǎn)就是可以將解決問(wèn)題的代碼隔離,聚攏在一點(diǎn);
【10.1】創(chuàng)建內(nèi)部類(lèi) 【荔枝】把類(lèi)的定義置于外圍類(lèi)的里面 public class Parcel1 {class Contents { // 內(nèi)部類(lèi)private int i = 11;public int value() {return i;}}class Destination { // 內(nèi)部類(lèi)private String label;Destination(String whereTo) {label = whereTo;}String readLabel() {return label;}}// Using inner classes looks just like// using any other class, within Parcel1:// public void ship(String dest) {Contents c = new Contents(); // Destination d = new Destination(dest);System.out.println(d.readLabel());}public static void main(String[] args) {Parcel1 p = new Parcel1();p.ship("Tasmania");} } /* Tasmania */ 【荔枝】外部類(lèi)有一個(gè)方法, 該方法返回一個(gè)指向內(nèi)部類(lèi)的引用, 如下: public class Parcel2 {class Contents { // 內(nèi)部類(lèi)private int i = 11;public int value() { return i; }}class Destination { // 內(nèi)部類(lèi)private String label;Destination(String whereTo) {label = whereTo;}String readLabel() { return label; }}public Destination to(String s) { // 外部類(lèi)中的方法 返回一個(gè)指向 內(nèi)部類(lèi)的引用return new Destination(s);}public Contents contents() { // 外部類(lèi)中的方法 返回一個(gè)指向 內(nèi)部類(lèi)的引用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(); // 注意它調(diào)用內(nèi)部類(lèi)的方式 是 Parcel2.ContentsParcel2.Destination d = q.to("Borneo"); // // 注意它調(diào)用內(nèi)部類(lèi)的方式 是 Parcel2.Destination} } /* Tasmania */ 【補(bǔ)充】如果想從外部類(lèi)的非靜態(tài)方法之外的任意位置創(chuàng)建某個(gè)內(nèi)部類(lèi)的對(duì)象, 那么必須像在main方法中那樣,具體指明這個(gè)對(duì)象的類(lèi)型: OuterClassName.InnerClassName;
【10.2】鏈接到外部類(lèi) 1)內(nèi)部類(lèi)擁有訪(fǎng)問(wèn)外圍類(lèi)的所有元素的訪(fǎng)問(wèn)權(quán);
【荔枝】基于內(nèi)部類(lèi)實(shí)現(xiàn)迭代器設(shè)計(jì)模式 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;}// 迭代器設(shè)計(jì)模式private class SequenceSelector implements Selector { // 內(nèi)部類(lèi) 訪(fǎng)問(wèn)外部類(lèi)的 items 實(shí)例變量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 void reverseSelector() { }}public Selector selector() { // 外部類(lèi)方法 創(chuàng)建內(nèi)部類(lèi)并返回該實(shí)例.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.print(selector.current() + " ");selector.next();}} } /** Output: 0 1 2 3 4 5 6 7 8 9*/// :~ 【補(bǔ)充】當(dāng)某個(gè)外圍類(lèi)的對(duì)象創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象時(shí),此內(nèi)部類(lèi)對(duì)象必定會(huì)秘密捕獲一個(gè)指向那個(gè)外圍類(lèi)對(duì)象的引用;然后,在你訪(fǎng)問(wèn)此外圍類(lèi)的成員時(shí), 就是用那個(gè)引用來(lái)選擇外圍類(lèi)的成員;
【10.3】使用.this(生成對(duì)外部類(lèi)對(duì)象的引用) 與 .new(在 new 表達(dá)式中提供對(duì)其他外部類(lèi)對(duì)象的引用) 【荔枝】如何使用 .this public class DotThis {void f() {System.out.println("DotThis.f()");}public class Inner { // 內(nèi)部類(lèi)public DotThis outer() {return DotThis.this; // key: 生成對(duì)外部類(lèi)對(duì)象的引用.}}public Inner inner() {return new Inner();}public static void main(String[] args) {DotThis dt = new DotThis();DotThis.Inner dti = dt.inner();dti.outer().f(); } } /** Output: DotThis.f()*/// :~ 【荔枝】如何使用.new public class DotNew {public class Inner { }public static void main(String[] args) {DotNew dn = new DotNew();// .new : 在new 表達(dá)式中 提供對(duì)其他外部類(lèi)對(duì)象的引用, 使用 .new 語(yǔ)法.DotNew.Inner dni = dn.new Inner(); }public void main2() {DotThis dt = new DotThis();DotThis.Inner inner = dt.new Inner();System.out.println(inner);} } // /:~ 【補(bǔ)充】 補(bǔ)充1)在擁有外部類(lèi)對(duì)象之前是不可能創(chuàng)建內(nèi)部類(lèi)對(duì)象的。這是因?yàn)閮?nèi)部類(lèi)對(duì)象會(huì)暗暗地連接到創(chuàng)建它的外部類(lèi)對(duì)象上; 補(bǔ)充2)如果創(chuàng)建的是靜態(tài)內(nèi)部類(lèi), 則靜態(tài)內(nèi)部類(lèi)不需要對(duì)外部類(lèi)對(duì)象的引用;
【荔枝】.new 應(yīng)用于 Parcel public class Parcel3 {class Contents { // 內(nèi)部類(lèi)private int i = 11;public int value() {return i;}}class Destination { // 內(nèi)部類(lèi)private String label;Destination(String whereTo) {label = whereTo;}String readLabel() {return label;}}public static void main(String[] args) {Parcel3 p = new Parcel3();// Must use instance of outer class// to create an instance of the inner class:// 必須使用外部類(lèi)對(duì)象實(shí)例 創(chuàng)建 內(nèi)部類(lèi)實(shí)例Parcel3.Contents c = p.new Contents();Parcel3.Destination d = p.new Destination("Tasmania");} } // /:~ 【10.4】?jī)?nèi)部類(lèi)與向上轉(zhuǎn)型 1)當(dāng)將內(nèi)部類(lèi)向上轉(zhuǎn)型為其基類(lèi), 尤其轉(zhuǎn)型為一個(gè)接口時(shí),內(nèi)部類(lèi)就有了用武之地;
【荔枝】?jī)?nèi)部類(lèi)向上轉(zhuǎn)型 // 荔枝:內(nèi)部類(lèi)向上轉(zhuǎn)型 class Parcel4 {// private 訪(fǎng)問(wèn)修飾符 的內(nèi)部類(lèi) 隱藏子類(lèi)的實(shí)現(xiàn)細(xì)節(jié).private class PContents implements Contents {private int i = 11;public int value() { return i; }}protected class PDestination implements Destination {private String label;private PDestination(String whereTo) { label = whereTo; }public String readLabel() { return label; }}public Destination destination(String s) {return new PDestination(s);}public Contents contents() {return new PContents();} } public class TestParcel {public static void main(String[] args) {Parcel4 p = new Parcel4();Contents c = p.contents(); // 內(nèi)部類(lèi)向上轉(zhuǎn)型.Destination d = p.destination("Tasmania");} } 【補(bǔ)充】 補(bǔ)充1)注意private內(nèi)部類(lèi)的訪(fǎng)問(wèn)權(quán)限;
【10.5】在方法和作用域內(nèi)的內(nèi)部類(lèi) 1)可以在一個(gè)方法里面或在任意的作用域內(nèi)定義內(nèi)部類(lèi);
【荔枝】局部?jī)?nèi)部類(lèi):在方法作用域內(nèi)創(chuàng)建一個(gè)完整的類(lèi) // 局部?jī)?nèi)部類(lèi)的經(jīng)典荔枝 public class Parcel5 {public Destination destination(String s) {class PDestination implements Destination { // 局部?jī)?nèi)部類(lèi),在方法中進(jìn)行定義private String label;private PDestination(String whereTo) {label = whereTo;}public String readLabel() {return label;}}return new PDestination(s); // 在同一個(gè)方法中 返回 局部?jī)?nèi)部類(lèi)的實(shí)例}public static void main(String[] args) {Parcel5 p = new Parcel5();Destination d = p.destination("Tasmania");} } // 【荔枝】如何在任意的作用域內(nèi)嵌入一個(gè)內(nèi)部類(lèi) // 荔枝:在任意作用域中嵌入一個(gè)內(nèi)部類(lèi). public class Parcel6 {private void internalTracking(boolean b) {if (b) { class TrackingSlip { // if 條件語(yǔ)句中 定義 局部?jī)?nèi)部類(lèi)private String id;TrackingSlip(String s) {id = s;}String getSlip() { return id; }}TrackingSlip ts = new TrackingSlip("slip");String s = ts.getSlip();System.out.println(s);} // 在 定義 TrackingSlip 的作用域之外 創(chuàng)建 TrackingSlip 實(shí)例是不可行的. // TrackingSlip instance = new TrackingSlip("str"); // syntax error.}public void track() {internalTracking(true);}public static void main(String[] args) {Parcel6 p = new Parcel6();p.track();} } 【10.6】匿名內(nèi)部類(lèi) 1)匿名內(nèi)部類(lèi)荔枝: public interface Contents {int value(); } // 荔枝-匿名內(nèi)部類(lèi) public class Parcel7 {public Contents contents() {return new Contents() { // 插入一個(gè)類(lèi)的定義 == 匿名內(nèi)部類(lèi)private int i = 11;public int value() {return i;}}; // 匿名內(nèi)部類(lèi)需要分號(hào).}public static void main(String[] args) {Parcel7 p = new Parcel7();Contents c = p.contents();} } 【補(bǔ)充】 補(bǔ)充1)contents方法將返回值的生成與表示這個(gè)返回值的類(lèi)的定義結(jié)合在一起; 補(bǔ)充2)匿名內(nèi)部類(lèi)語(yǔ)法說(shuō)明: 創(chuàng)建一個(gè)繼承自Contents的匿名類(lèi)的對(duì)象; 通過(guò)new表達(dá)式返回的引用被自動(dòng)向上轉(zhuǎn)型為 對(duì) Contents的引用;
【荔枝】上述匿名內(nèi)部類(lèi)(Parcel7.java)的語(yǔ)法是以下代碼的簡(jiǎn)化版本,如下: // 匿名內(nèi)部類(lèi)的等同版本(不過(guò)本版本要比匿名內(nèi)部類(lèi)復(fù)雜得多) public class Parcel7b {// 創(chuàng)建一個(gè)繼承自 Contents 的 匿名類(lèi)的對(duì)象class MyContents implements Contents {private int i = 11;public int value() {return i;}}// 創(chuàng)建方法返回的引用被自動(dòng) 向上轉(zhuǎn)型為 對(duì) Contents 的 引用public Contents contents() {return new MyContents();}public static void main(String[] args) {Parcel7b p = new Parcel7b();Contents c = p.contents();} } 以上代碼使用了默認(rèn)構(gòu)造器來(lái)生成 Contents對(duì)象, 如果構(gòu)造器是有參數(shù)的, 怎么辦?
【荔枝】基于有參構(gòu)造器定義匿名內(nèi)部類(lèi) public class Wrapping {private int i;public Wrapping(int x) { i = x; }public int value() { return i; } } // 荔枝-基于有參構(gòu)造器 定義匿名內(nèi)部類(lèi) public class Parcel8 {public Wrapping wrapping(int x) {return new Wrapping(x) { // 傳遞給有參構(gòu)造器. public int value() {return super.value() * 47; // super.value() 是基類(lèi)方法返回值}}; // 匿名內(nèi)部類(lèi)需要分號(hào)}public static void main(String[] args) {Parcel8 p = new Parcel8();Wrapping w = p.wrapping(10);System.out.println(w.value());} } 【荔枝】在匿名內(nèi)部類(lèi)中定義字段時(shí), 可以對(duì)其執(zhí)行初始化操作 // 荔枝-在匿名內(nèi)部類(lèi)中定義字段時(shí), 可以對(duì)其執(zhí)行初始化操作 public class Parcel9 {// 希望 匿名內(nèi)部類(lèi) 使用一個(gè) 在其外部定義的 對(duì)象,其參數(shù)引用必須為finalpublic Destination destination(final String dest) { return new Destination() {private String label = dest;public String readLabel() { return label; }}; // 需要分號(hào)}public static void main(String[] args) {Parcel9 p = new Parcel9();Destination d = p.destination("Tasmania");System.out.println(d.readLabel());}public static void f1() {}public void f2(){ f1(); } } /* Tasmania */ 【補(bǔ)充】希望 匿名內(nèi)部類(lèi) 使用一個(gè) 在其外部定義的 對(duì)象,其參數(shù)引用必須為final
在匿名內(nèi)部類(lèi)中不可能有命名構(gòu)造器(因?yàn)樗緵](méi)名字)。但通過(guò)實(shí)例初始化, 就能夠達(dá)到為匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器的效果,就像這樣: 【荔枝】通過(guò)實(shí)例初始化為匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器 // 荔枝-通過(guò)實(shí)例初始化為匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器 abstract class Base {public Base(int i) { print("Base constructor, i = " + i); }public abstract void f(); } public class AnonymousConstructor {public static Base getBase(int i) {// 通過(guò)實(shí)例初始化, 就能夠達(dá)到為 匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器的效果.return new Base(i) {{print("Inside instance initializer");}public void f() {print("In anonymous f(), and i = " + i);}};}public static void main(String[] args) {Base base = getBase(47);base.f();} } /* Base constructor, i = 47 Inside instance initializer In anonymous f(), and i = 47 */ 【補(bǔ)充】在上述荔枝中, 不要求變量i一定是final的。因?yàn)?i 被傳遞給匿名類(lèi)的基類(lèi)構(gòu)造器, 他并不會(huì)在匿名內(nèi)部類(lèi)的內(nèi)部被直接使用;
【荔枝】為內(nèi)部類(lèi)字段進(jìn)行賦值,則方法參數(shù)必須是 final // 荔枝-為內(nèi)部類(lèi)字段進(jìn)行賦值, 則方法參數(shù) 必須是 final public class Parcel10 { // 為內(nèi)部類(lèi)字段進(jìn)行賦值, 則方法參數(shù) 必須是 finalpublic Destination destination(final String dest, final float price) {return new Destination() {private int cost;// 對(duì)每個(gè)對(duì)象進(jìn)行初始化{cost = Math.round(price); // 四舍五入if (cost > 100)System.out.println("Over budget!");}private String label = dest;public String readLabel() {return label;}};}public static void main(String[] args) {Parcel10 p = new Parcel10();Destination d = p.destination("Tasmania", 101.395F);System.out.println(d.readLabel());} } /* Over budget! Tasmania */ 【補(bǔ)充】匿名內(nèi)部類(lèi)與正規(guī)的繼承相比有些受限:因?yàn)槟涿麅?nèi)部類(lèi)既可以擴(kuò)展類(lèi),也可以實(shí)現(xiàn)接口,但不能兩者兼?zhèn)洹H绻麑?shí)現(xiàn)接口,也只能實(shí)現(xiàn)一個(gè)接口;
【10.6.1】在訪(fǎng)工廠方法 【荔枝】基于匿名內(nèi)部類(lèi)的工廠方法 interface Service { void method1(); void method2(); } interface ServiceFactory { Service getService(); } // 荔枝-通過(guò)匿名內(nèi)部類(lèi) 實(shí)現(xiàn)工廠方法模式(經(jīng)典荔枝) class Implementation1 implements Service {private Implementation1() { }public void method1() { print("Implementation1 method1"); }public void method2() { print("Implementation1 method2"); }public static ServiceFactory factory = new ServiceFactory() { // 靜態(tài)匿名內(nèi)部類(lèi)public Service getService() { return new Implementation1(); }}; } class Implementation2 implements Service {private Implementation2() { }public void method1() { print("Implementation2 method1"); }public void method2() { print("Implementation2 method2"); }public static ServiceFactory factory = new ServiceFactory() { // 靜態(tài)匿名內(nèi)部類(lèi)public Service getService() { return new Implementation2(); }}; } public class Factories {public static void serviceConsumer(ServiceFactory fact) {Service s = fact.getService();s.method1();s.method2();}public static void main(String[] args) {serviceConsumer(Implementation1.factory);serviceConsumer(Implementation2.factory);} } /** Output: * Implementation1 method1 * Implementation1 method2 * Implementation2 method1* Implementation2 method2*/// :~ 【荔枝】通過(guò)匿名內(nèi)部類(lèi) 實(shí)現(xiàn)工廠方法模式(經(jīng)典荔枝) interface Game { boolean move(); } interface GameFactory { Game getGame(); } //通過(guò)匿名內(nèi)部類(lèi) 實(shí)現(xiàn)工廠方法模式(經(jīng)典荔枝) class Checkers implements Game {private Checkers() {}private int moves = 0;private static final int MOVES = 3;public boolean move() {print("Checkers move " + moves);return ++moves != MOVES;}public static GameFactory factory = new GameFactory() { // 匿名內(nèi)部類(lèi).public Game getGame() { return new Checkers(); }}; } class Chess implements Game {private Chess() {}private int moves = 0;private static final int MOVES = 4;public boolean move() {print("Chess move " + moves);return ++moves != MOVES;}public static GameFactory factory = new GameFactory() { // 匿名內(nèi)部類(lèi).public Game getGame() { return new Chess(); }}; } public class Games {public static void playGame(GameFactory factory) {Game s = factory.getGame();while (s.move()) ;}public static void main(String[] args) {playGame(Checkers.factory);playGame(Chess.factory);} } /* Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 */ 【10.7】嵌套類(lèi)(靜態(tài)內(nèi)部類(lèi)) 1)靜態(tài)內(nèi)部類(lèi)意味著: 1.1)要?jiǎng)?chuàng)建匿名內(nèi)部類(lèi)的對(duì)象,并不需要其外圍類(lèi)對(duì)象; 1.2)不能從匿名內(nèi)部類(lèi)的對(duì)象中訪(fǎng)問(wèn)非靜態(tài)的外圍類(lèi)對(duì)象; 2)靜態(tài)內(nèi)部類(lèi)與普通內(nèi)部類(lèi)的區(qū)別:普通內(nèi)部類(lèi)的字段與方法, 只能放在類(lèi)的外部層次上, 所以普通內(nèi)部類(lèi)不能有static數(shù)據(jù)和static字段,也不能包含 靜態(tài)內(nèi)部類(lèi)。 但是靜態(tài)內(nèi)部類(lèi)里是可以包含所有這些東西的;
【荔枝】靜態(tài)內(nèi)部類(lèi)可以包含static數(shù)據(jù),static字段和方法,也可以包含普通的字段和方法 // 嵌套類(lèi)(靜態(tài)內(nèi)部類(lèi))的荔枝 public class Parcel11 {// 靜態(tài)內(nèi)部類(lèi)private static class ParcelContents implements Contents {private int i = 11;public int value() { return i; }}// 靜態(tài)內(nèi)部類(lèi)protected static class ParcelDestination implements Destination {private String label; // 普通變量private ParcelDestination(String whereTo) {label = whereTo;}public String readLabel() { // 普通方法return label;}public static void f() { } // 靜態(tài)方法static int x = 10; // 靜態(tài)變量static class AnotherLevel { // 靜態(tài)內(nèi)部類(lèi)( 嵌套類(lèi) )public static void f() { } // 靜態(tài)方法static int x = 10; // 靜態(tài)變量int y = 10; // 普通變量}class A { // 普通內(nèi)部類(lèi)class B {class C { }}}}public static Destination destination(String s) {return new ParcelDestination(s);}public static Contents contents() {return new ParcelContents();}public static void main(String[] args) {Contents c = contents();Destination d = destination("Tasmania");} } 【10.7.1】接口內(nèi)部的類(lèi) 1)正常情況下, 不能在接口內(nèi)部放置任何代碼,但靜態(tài)內(nèi)部類(lèi)可以作為接口的一部分; 2)放置到接口中的任何類(lèi)都默認(rèn)是 public static;
【荔枝】在接口內(nèi)部定義靜態(tài)內(nèi)部類(lèi) // 在接口作用域內(nèi)放置 嵌套類(lèi)(靜態(tài)內(nèi)部類(lèi)) // 接口中的類(lèi) 自動(dòng)是 public 和 static 的. interface ClassInInterface{void howdy();class Test implements ClassInInterface { // 默認(rèn)是 public staticpublic void howdy() {System.out.println("Howdy!");}public static void test() {System.out.println("my name is test.");}public static void main(String[] args) {new Test().howdy(); }} } /* 錯(cuò)誤: 找不到或無(wú)法加載主類(lèi) chapter10.ClassInInterfaceTest$Test */ 【補(bǔ)充】在每個(gè)類(lèi)中都寫(xiě)main方法來(lái)測(cè)試。這樣做有一個(gè)缺點(diǎn): 那就是必須帶著那些已經(jīng)編譯過(guò)的額外代碼。如果這對(duì)你是個(gè)麻煩,那就可以使用匿名內(nèi)部類(lèi)來(lái)放置測(cè)試代碼; //荔枝-使用匿名內(nèi)部類(lèi)來(lái)放置測(cè)試代碼 public class TestBed {public void f() {System.out.println("f()");}public static class Tester {public static void main(String[] args) {TestBed t = new TestBed();t.f();}} } /** Output: f()*/ 【說(shuō)明】這生成了一個(gè)獨(dú)立的類(lèi) TestBed$Tester(要運(yùn)行這個(gè)程序, 執(zhí)行 java TestBed$Tester 即可);可以使用這個(gè)類(lèi)來(lái)做測(cè)試, 但不必再發(fā)布的產(chǎn)品中包含它, 在將產(chǎn)品打包前可以簡(jiǎn)單地刪除 TestBed$Tester.class; 【10.7.2】從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部類(lèi)的成員 1)一個(gè)內(nèi)部類(lèi)被嵌套多少層并不重要:它能透明地訪(fǎng)問(wèn)所有它所嵌入的外圍類(lèi)的所有成員;
【荔枝】從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部類(lèi)的成員 // 荔枝-從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部類(lèi)的成員 class MNA {private void f() {}class A {private void g() {}public class B {// 從多層嵌套類(lèi)中 訪(fǎng)問(wèn)外部類(lèi)的成員.void h() {g(); // 調(diào)用 A.g()f(); // 調(diào)用 MNA.f()}}} }public class MultiNestingAccess {public static void main(String[] args) {MNA mna = new MNA();MNA.A mnaa = mna.new A(); // .new 表達(dá)式提供對(duì)其他外部類(lèi)對(duì)象的引用.MNA.A.B mnaab = mnaa.new B();mnaab.h();} } // /:~ 【10.8】為什么需要內(nèi)部類(lèi)? 1)內(nèi)部類(lèi)最吸引人的原因: 每個(gè)內(nèi)部類(lèi)都能獨(dú)立繼承自一個(gè)(接口的)實(shí)現(xiàn), 所以無(wú)論外圍類(lèi)是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn), 對(duì)于內(nèi)部類(lèi)都沒(méi)有影響; 2)內(nèi)部類(lèi)使得多重繼承的解決方案變得完整。接口解決了多重繼承的部分問(wèn)題, 內(nèi)部類(lèi)有效地實(shí)現(xiàn)了 多重繼承。也就是說(shuō), 內(nèi)部類(lèi)允許繼承多個(gè)非接口類(lèi)型(譯注:類(lèi)或抽象類(lèi));
3)考慮以下情形:必須在一個(gè)類(lèi)中以某種方式實(shí)現(xiàn)兩個(gè)接口。 有兩種實(shí)現(xiàn)方式:使用單一類(lèi), 或者使用內(nèi)部類(lèi); // 荔枝-實(shí)現(xiàn)多重接口的荔枝 // 方式1-使用單一類(lèi) class X implements A, B {}// 方式2-使用內(nèi)部類(lèi), 如下: // 外部類(lèi)本身實(shí)現(xiàn)一個(gè)接口; // 外部類(lèi)的方法返回一個(gè)匿名內(nèi)部類(lèi)(匿名內(nèi)部類(lèi)就是一個(gè)接口類(lèi)型), 以達(dá)到實(shí)現(xiàn)兩個(gè)接口的目的; class Y implements A {B makeB() {// 匿名內(nèi)部類(lèi)return new B() {};} } public class MultiInterfaces {static void takesA(A a) {}static void takesB(B b) {}public static void main(String[] args) {X x = new X();Y y = new Y();takesA(x);takesA(y);takesB(x);takesB(y.makeB()); // this line.(bingo)} } 4)如果擁有的是抽象類(lèi)或具體類(lèi),而不是接口, 那就只能使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承; (干貨——使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承)
【荔枝】使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承 class D {} // 具體類(lèi) abstract class E {} // 抽象類(lèi)// 荔枝-使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承 class Z extends D {E makeE() {return new E() {};} }public class MultiImplementation {static void takesD(D d) {}static void takesE(E e) {}public static void main(String[] args) {Z z = new Z();takesD(z);takesE(z.makeE());} } 5)內(nèi)部類(lèi)有以下特性: 特性1)內(nèi)部類(lèi)可以有多個(gè)實(shí)例, 每個(gè)實(shí)例都有自己的狀態(tài)信息,并且與其外圍類(lèi)對(duì)象的信息相互獨(dú)立; 特性2)在單個(gè)外圍類(lèi)中, 可以讓多個(gè)內(nèi)部類(lèi)以不同方式實(shí)現(xiàn)同一個(gè)接口,或繼承同一個(gè)類(lèi); 特性3)創(chuàng)建內(nèi)部類(lèi)對(duì)象的時(shí)刻并不依賴(lài)于外圍類(lèi)對(duì)象的創(chuàng)建; 特性4)內(nèi)部類(lèi)并沒(méi)有 is-a 關(guān)系, 他就是一個(gè)獨(dú)立實(shí)體;
【10.8.1】閉包與回調(diào) 1)閉包是一個(gè)可調(diào)用的對(duì)象,他記錄了一些信息,這些信息來(lái)自于創(chuàng)建它的作用域; 2)內(nèi)部類(lèi)是面向?qū)ο蟮拈]包: 因?yàn)閮?nèi)部類(lèi)不僅包含外圍類(lèi)對(duì)象(創(chuàng)建內(nèi)部類(lèi)的作用域)的信息,還自動(dòng)擁有一個(gè)指向指向此外圍類(lèi)對(duì)象的引用,在此作用域內(nèi),內(nèi)部類(lèi)有權(quán)操作所有成員,包括private成員;
【荔枝】通過(guò)內(nèi)部類(lèi)提供閉包功能 // 荔枝-通過(guò)內(nèi)部類(lèi)提供閉包功能 interface Incrementable { void increment(); } // 類(lèi)本身實(shí)現(xiàn)接口 class Callee1 implements Incrementable {private int i = 0;public void increment() { i++; print(i); } }class MyIncrement {public void increment() { print("Other operation"); }static void f(MyIncrement mi) { mi.increment(); } } // 類(lèi)的內(nèi)部類(lèi)實(shí)現(xiàn)接口 class Callee2 extends MyIncrement {private int i = 0;@Overridepublic void increment() {super.increment(); i++; print(i);}// 閉包內(nèi)部類(lèi)private class Closure implements Incrementable {public void increment() {// 指定外部類(lèi)方法,否則你將得到一個(gè)無(wú)限循環(huán).Callee2.this.increment(); // 返回外部類(lèi)對(duì)象的引用(鉤子),利用鉤子調(diào)用外部類(lèi)的方法,稱(chēng)為回調(diào)}}// 返回回調(diào)引用Incrementable getCallbackReference() { 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); // Other operation 1Caller caller1 = new Caller(c1);Caller caller2 = new Caller(c2.getCallbackReference()); // 獲得回調(diào)引用caller1.go(); // 1 caller1.go(); // 2caller2.go(); // Other operation 2caller2.go(); // Other operation 3} } /* Other operation 1 1 2 Other operation 2 Other operation 3 */ 分析1)內(nèi)部類(lèi)Closure 實(shí)現(xiàn)了 Incrementable接口,以提供返回 Callee2的鉤子; 分析2)Caller的構(gòu)造器需要一個(gè) Incrementable 的引用作為參數(shù)(雖然可以在任意時(shí)刻捕獲回調(diào)引用),然后在以后的某個(gè)時(shí)刻,Caller對(duì)象可以使用此引用回調(diào)Callee類(lèi);
【10.9】?jī)?nèi)部類(lèi)的繼承 // 荔枝-內(nèi)部類(lèi)的繼承 class WithInner {class Inner {} }public class InheritInner extends WithInner.Inner {// InheritInner() {} // 這個(gè)無(wú)參構(gòu)造器 無(wú)法編譯,Won't compileInheritInner(WithInner wi) {wi.super();}public static void main(String[] args) {WithInner wi = new WithInner();InheritInner ii = new InheritInner(wi);} } // /:~ 分析1)InheritInner只繼承自?xún)?nèi)部類(lèi),而不是外圍類(lèi); 分析2)當(dāng)要生成一個(gè)構(gòu)造器時(shí),默認(rèn)的構(gòu)造器并不算好,而且不能只是傳遞一個(gè)指向外圍類(lèi)對(duì)象的引用。 分析3)必須在構(gòu)造器內(nèi)使用如下語(yǔ)法: enclosingClassReference.super(); 這樣才提供了必要的引用, 然后程序才能通過(guò)編譯;
【10.10】?jī)?nèi)部類(lèi)可以被覆蓋嗎? 1)內(nèi)部類(lèi)覆蓋:如果創(chuàng)建一個(gè)內(nèi)部類(lèi),然后繼承其外圍類(lèi)并重新定義此內(nèi)部類(lèi)時(shí),會(huì)發(fā)生什么呢? 2)覆蓋內(nèi)部類(lèi)并不起什么作用; // 荔枝-覆蓋內(nèi)部類(lèi)(不起任何作用) class Egg {private Yolk y;protected class Yolk {public Yolk() { print("Egg.Yolk()"); } // 2, 而是調(diào)用這個(gè) Yolk 構(gòu)造方法。}public Egg() {print("New Egg()"); // 1y = new Yolk();} }public class BigEgg extends Egg {// 內(nèi)部類(lèi) BigEgg.Yolk 沒(méi)有覆蓋 內(nèi)部類(lèi) Egg.Yolk public class Yolk {public Yolk() { print("BigEgg.Yolk()"); } // not this one. 并沒(méi)有調(diào)用這個(gè) Yolk 構(gòu)造方法。}public static void main(String[] args) {new BigEgg();} } /* New Egg() Egg.Yolk() */ 3)明確地繼承某個(gè)內(nèi)部類(lèi)是奏效的, 如下: // 荔枝-明確地繼承某個(gè)內(nèi)部類(lèi)是奏效的 class Egg2 {protected class Yolk {public Yolk() { print("Egg2.Yolk()"); } // 1, 3public void f() { print("Egg2.Yolk.f()"); }}private Yolk y = new Yolk();public Egg2() { print("New Egg2()"); } // 2public void insertYolk(Yolk yy) { y = yy; }public void g() { y.f(); } }public class BigEgg2 extends Egg2 {// 內(nèi)部類(lèi) BigEgg2.Yolk 明確繼承繼承 另一個(gè)外部類(lèi)的內(nèi)部類(lèi) Egg2.Yolkpublic class Yolk extends Egg2.Yolk {public Yolk() { print("BigEgg2.Yolk()"); } // 4public void f() { print("BigEgg2.Yolk.f()"); } // 5}public BigEgg2() { insertYolk(new Yolk()); }public static void main(String[] args) {Egg2 e2 = new BigEgg2();e2.g();} } /* Egg2.Yolk() New Egg2() Egg2.Yolk() BigEgg2.Yolk() BigEgg2.Yolk.f() */ 【10.11】局部?jī)?nèi)部類(lèi) 1)介紹: 局部?jī)?nèi)部類(lèi)不能有訪(fǎng)問(wèn)說(shuō)明符,因?yàn)樗皇峭鈬?lèi)的一部分;但是他可以訪(fǎng)問(wèn)當(dāng)前代碼塊內(nèi)的常量,以及此外圍類(lèi)的所有成員; 2)對(duì)局部?jī)?nèi)部類(lèi)與匿名內(nèi)部類(lèi)的創(chuàng)建進(jìn)行了比較,荔枝如下: // 荔枝-局部?jī)?nèi)部類(lèi) // 荔枝-對(duì)局部?jī)?nèi)部類(lèi)與匿名內(nèi)部類(lèi)的創(chuàng)建進(jìn)行了比較 interface Counter { int next(); } public class LocalInnerClass {private int count = 0;Counter getCounter(final String name) {class LocalCounter implements Counter { // 方法域中聲明 局部?jī)?nèi)部類(lèi)public LocalCounter() { print("LocalCounter()"); }public int next() {printnb(name); return count++; // 共同操作 外部類(lèi)的字段}}return new LocalCounter();}Counter getCounter2(final String name) {return new Counter() { // 匿名內(nèi)部類(lèi)完成 與 局部?jī)?nèi)部類(lèi)相同的工作{ print("Counter()"); }public int next() {printnb(name); return count++; // 共同操作 外部類(lèi)的字段}};}public static void main(String[] args) {LocalInnerClass lic = new LocalInnerClass();Counter c1 = lic.getCounter("Local inner "), c2 = lic.getCounter2("Anonymous inner ");for (int i = 0; i < 5; i++)print(c1.next());for (int i = 0; i < 5; i++)print(c2.next());} } /* LocalCounter() Counter() Local inner 0 Local inner 1 Local inner 2 Local inner 3 Local inner 4 Anonymous inner 5 Anonymous inner 6 Anonymous inner 7 Anonymous inner 8 Anonymous inner 9 */ 【補(bǔ)充】為什么有些時(shí)候仍然使用局部?jī)?nèi)部類(lèi),不是已經(jīng)有匿名內(nèi)部類(lèi)了嗎? 理由1)需要一個(gè)已命名的構(gòu)造器,或者需要重載構(gòu)造器,而匿名內(nèi)部類(lèi)只能用于實(shí)例化; 理由2)需要不止一個(gè)該內(nèi)部類(lèi)的對(duì)象;
【10.12】?jī)?nèi)部類(lèi)標(biāo)識(shí)符 1)內(nèi)部類(lèi)生成一個(gè) .class文件以包含他們的 Class 對(duì)象信息; 2)這些類(lèi)文件的命名有嚴(yán)格的規(guī)則: 外圍類(lèi)的名字, 加上 $ , 再加上內(nèi)部類(lèi)的名字; 3)荔枝: LocalInnerClass.java 生成的 .class 文件包括: Counter.class // 接口 LocalInnerClass$1.class // 匿名內(nèi)部類(lèi) LocalInnerClass$1LocalCounter.class // 局部?jī)?nèi)部類(lèi) LocalInnerClass.class // LocalInnerClass類(lèi)
【10.1】創(chuàng)建內(nèi)部類(lèi) 【荔枝】把類(lèi)的定義置于外圍類(lèi)的里面 public class Parcel1 {class Contents { // 內(nèi)部類(lèi)private int i = 11;public int value() {return i;}}class Destination { // 內(nèi)部類(lèi)private String label;Destination(String whereTo) {label = whereTo;}String readLabel() {return label;}}// Using inner classes looks just like// using any other class, within Parcel1:// public void ship(String dest) {Contents c = new Contents(); // Destination d = new Destination(dest);System.out.println(d.readLabel());}public static void main(String[] args) {Parcel1 p = new Parcel1();p.ship("Tasmania");} } /* Tasmania */ 【荔枝】外部類(lèi)有一個(gè)方法, 該方法返回一個(gè)指向內(nèi)部類(lèi)的引用, 如下: public class Parcel2 {class Contents { // 內(nèi)部類(lèi)private int i = 11;public int value() { return i; }}class Destination { // 內(nèi)部類(lèi)private String label;Destination(String whereTo) {label = whereTo;}String readLabel() { return label; }}public Destination to(String s) { // 外部類(lèi)中的方法 返回一個(gè)指向 內(nèi)部類(lèi)的引用return new Destination(s);}public Contents contents() { // 外部類(lèi)中的方法 返回一個(gè)指向 內(nèi)部類(lèi)的引用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(); // 注意它調(diào)用內(nèi)部類(lèi)的方式 是 Parcel2.ContentsParcel2.Destination d = q.to("Borneo"); // // 注意它調(diào)用內(nèi)部類(lèi)的方式 是 Parcel2.Destination} } /* Tasmania */ 【補(bǔ)充】如果想從外部類(lèi)的非靜態(tài)方法之外的任意位置創(chuàng)建某個(gè)內(nèi)部類(lèi)的對(duì)象, 那么必須像在main方法中那樣,具體指明這個(gè)對(duì)象的類(lèi)型: OuterClassName.InnerClassName;
【10.2】鏈接到外部類(lèi) 1)內(nèi)部類(lèi)擁有訪(fǎng)問(wèn)外圍類(lèi)的所有元素的訪(fǎng)問(wèn)權(quán);
【荔枝】基于內(nèi)部類(lèi)實(shí)現(xiàn)迭代器設(shè)計(jì)模式 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;}// 迭代器設(shè)計(jì)模式private class SequenceSelector implements Selector { // 內(nèi)部類(lèi) 訪(fǎng)問(wèn)外部類(lèi)的 items 實(shí)例變量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 void reverseSelector() { }}public Selector selector() { // 外部類(lèi)方法 創(chuàng)建內(nèi)部類(lèi)并返回該實(shí)例.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.print(selector.current() + " ");selector.next();}} } /** Output: 0 1 2 3 4 5 6 7 8 9*/// :~ 【補(bǔ)充】當(dāng)某個(gè)外圍類(lèi)的對(duì)象創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象時(shí),此內(nèi)部類(lèi)對(duì)象必定會(huì)秘密捕獲一個(gè)指向那個(gè)外圍類(lèi)對(duì)象的引用;然后,在你訪(fǎng)問(wèn)此外圍類(lèi)的成員時(shí), 就是用那個(gè)引用來(lái)選擇外圍類(lèi)的成員;
【10.3】使用.this(生成對(duì)外部類(lèi)對(duì)象的引用) 與 .new(在 new 表達(dá)式中提供對(duì)其他外部類(lèi)對(duì)象的引用) 【荔枝】如何使用 .this public class DotThis {void f() {System.out.println("DotThis.f()");}public class Inner { // 內(nèi)部類(lèi)public DotThis outer() {return DotThis.this; // key: 生成對(duì)外部類(lèi)對(duì)象的引用.}}public Inner inner() {return new Inner();}public static void main(String[] args) {DotThis dt = new DotThis();DotThis.Inner dti = dt.inner();dti.outer().f(); } } /** Output: DotThis.f()*/// :~ 【荔枝】如何使用.new public class DotNew {public class Inner { }public static void main(String[] args) {DotNew dn = new DotNew();// .new : 在new 表達(dá)式中 提供對(duì)其他外部類(lèi)對(duì)象的引用, 使用 .new 語(yǔ)法.DotNew.Inner dni = dn.new Inner(); }public void main2() {DotThis dt = new DotThis();DotThis.Inner inner = dt.new Inner();System.out.println(inner);} } // /:~ 【補(bǔ)充】 補(bǔ)充1)在擁有外部類(lèi)對(duì)象之前是不可能創(chuàng)建內(nèi)部類(lèi)對(duì)象的。這是因?yàn)閮?nèi)部類(lèi)對(duì)象會(huì)暗暗地連接到創(chuàng)建它的外部類(lèi)對(duì)象上; 補(bǔ)充2)如果創(chuàng)建的是靜態(tài)內(nèi)部類(lèi), 則靜態(tài)內(nèi)部類(lèi)不需要對(duì)外部類(lèi)對(duì)象的引用;
【荔枝】.new 應(yīng)用于 Parcel public class Parcel3 {class Contents { // 內(nèi)部類(lèi)private int i = 11;public int value() {return i;}}class Destination { // 內(nèi)部類(lèi)private String label;Destination(String whereTo) {label = whereTo;}String readLabel() {return label;}}public static void main(String[] args) {Parcel3 p = new Parcel3();// Must use instance of outer class// to create an instance of the inner class:// 必須使用外部類(lèi)對(duì)象實(shí)例 創(chuàng)建 內(nèi)部類(lèi)實(shí)例Parcel3.Contents c = p.new Contents();Parcel3.Destination d = p.new Destination("Tasmania");} } // /:~ 【10.4】?jī)?nèi)部類(lèi)與向上轉(zhuǎn)型 1)當(dāng)將內(nèi)部類(lèi)向上轉(zhuǎn)型為其基類(lèi), 尤其轉(zhuǎn)型為一個(gè)接口時(shí),內(nèi)部類(lèi)就有了用武之地;
【荔枝】?jī)?nèi)部類(lèi)向上轉(zhuǎn)型 // 荔枝:內(nèi)部類(lèi)向上轉(zhuǎn)型 class Parcel4 {// private 訪(fǎng)問(wèn)修飾符 的內(nèi)部類(lèi) 隱藏子類(lèi)的實(shí)現(xiàn)細(xì)節(jié).private class PContents implements Contents {private int i = 11;public int value() { return i; }}protected class PDestination implements Destination {private String label;private PDestination(String whereTo) { label = whereTo; }public String readLabel() { return label; }}public Destination destination(String s) {return new PDestination(s);}public Contents contents() {return new PContents();} } public class TestParcel {public static void main(String[] args) {Parcel4 p = new Parcel4();Contents c = p.contents(); // 內(nèi)部類(lèi)向上轉(zhuǎn)型.Destination d = p.destination("Tasmania");} } 【補(bǔ)充】 補(bǔ)充1)注意private內(nèi)部類(lèi)的訪(fǎng)問(wèn)權(quán)限;
【10.5】在方法和作用域內(nèi)的內(nèi)部類(lèi) 1)可以在一個(gè)方法里面或在任意的作用域內(nèi)定義內(nèi)部類(lèi);
【荔枝】局部?jī)?nèi)部類(lèi):在方法作用域內(nèi)創(chuàng)建一個(gè)完整的類(lèi) // 局部?jī)?nèi)部類(lèi)的經(jīng)典荔枝 public class Parcel5 {public Destination destination(String s) {class PDestination implements Destination { // 局部?jī)?nèi)部類(lèi),在方法中進(jìn)行定義private String label;private PDestination(String whereTo) {label = whereTo;}public String readLabel() {return label;}}return new PDestination(s); // 在同一個(gè)方法中 返回 局部?jī)?nèi)部類(lèi)的實(shí)例}public static void main(String[] args) {Parcel5 p = new Parcel5();Destination d = p.destination("Tasmania");} } // 【荔枝】如何在任意的作用域內(nèi)嵌入一個(gè)內(nèi)部類(lèi) // 荔枝:在任意作用域中嵌入一個(gè)內(nèi)部類(lèi). public class Parcel6 {private void internalTracking(boolean b) {if (b) { class TrackingSlip { // if 條件語(yǔ)句中 定義 局部?jī)?nèi)部類(lèi)private String id;TrackingSlip(String s) {id = s;}String getSlip() { return id; }}TrackingSlip ts = new TrackingSlip("slip");String s = ts.getSlip();System.out.println(s);} // 在 定義 TrackingSlip 的作用域之外 創(chuàng)建 TrackingSlip 實(shí)例是不可行的. // TrackingSlip instance = new TrackingSlip("str"); // syntax error.}public void track() {internalTracking(true);}public static void main(String[] args) {Parcel6 p = new Parcel6();p.track();} } 【10.6】匿名內(nèi)部類(lèi) 1)匿名內(nèi)部類(lèi)荔枝: public interface Contents {int value(); } // 荔枝-匿名內(nèi)部類(lèi) public class Parcel7 {public Contents contents() {return new Contents() { // 插入一個(gè)類(lèi)的定義 == 匿名內(nèi)部類(lèi)private int i = 11;public int value() {return i;}}; // 匿名內(nèi)部類(lèi)需要分號(hào).}public static void main(String[] args) {Parcel7 p = new Parcel7();Contents c = p.contents();} } 【補(bǔ)充】 補(bǔ)充1)contents方法將返回值的生成與表示這個(gè)返回值的類(lèi)的定義結(jié)合在一起; 補(bǔ)充2)匿名內(nèi)部類(lèi)語(yǔ)法說(shuō)明: 創(chuàng)建一個(gè)繼承自Contents的匿名類(lèi)的對(duì)象; 通過(guò)new表達(dá)式返回的引用被自動(dòng)向上轉(zhuǎn)型為 對(duì) Contents的引用;
【荔枝】上述匿名內(nèi)部類(lèi)(Parcel7.java)的語(yǔ)法是以下代碼的簡(jiǎn)化版本,如下: // 匿名內(nèi)部類(lèi)的等同版本(不過(guò)本版本要比匿名內(nèi)部類(lèi)復(fù)雜得多) public class Parcel7b {// 創(chuàng)建一個(gè)繼承自 Contents 的 匿名類(lèi)的對(duì)象class MyContents implements Contents {private int i = 11;public int value() {return i;}}// 創(chuàng)建方法返回的引用被自動(dòng) 向上轉(zhuǎn)型為 對(duì) Contents 的 引用public Contents contents() {return new MyContents();}public static void main(String[] args) {Parcel7b p = new Parcel7b();Contents c = p.contents();} } 以上代碼使用了默認(rèn)構(gòu)造器來(lái)生成 Contents對(duì)象, 如果構(gòu)造器是有參數(shù)的, 怎么辦?
【荔枝】基于有參構(gòu)造器定義匿名內(nèi)部類(lèi) public class Wrapping {private int i;public Wrapping(int x) { i = x; }public int value() { return i; } } // 荔枝-基于有參構(gòu)造器 定義匿名內(nèi)部類(lèi) public class Parcel8 {public Wrapping wrapping(int x) {return new Wrapping(x) { // 傳遞給有參構(gòu)造器. public int value() {return super.value() * 47; // super.value() 是基類(lèi)方法返回值}}; // 匿名內(nèi)部類(lèi)需要分號(hào)}public static void main(String[] args) {Parcel8 p = new Parcel8();Wrapping w = p.wrapping(10);System.out.println(w.value());} } 【荔枝】在匿名內(nèi)部類(lèi)中定義字段時(shí), 可以對(duì)其執(zhí)行初始化操作 // 荔枝-在匿名內(nèi)部類(lèi)中定義字段時(shí), 可以對(duì)其執(zhí)行初始化操作 public class Parcel9 {// 希望 匿名內(nèi)部類(lèi) 使用一個(gè) 在其外部定義的 對(duì)象,其參數(shù)引用必須為finalpublic Destination destination(final String dest) { return new Destination() {private String label = dest;public String readLabel() { return label; }}; // 需要分號(hào)}public static void main(String[] args) {Parcel9 p = new Parcel9();Destination d = p.destination("Tasmania");System.out.println(d.readLabel());}public static void f1() {}public void f2(){ f1(); } } /* Tasmania */ 【補(bǔ)充】希望 匿名內(nèi)部類(lèi) 使用一個(gè) 在其外部定義的 對(duì)象,其參數(shù)引用必須為final
在匿名內(nèi)部類(lèi)中不可能有命名構(gòu)造器(因?yàn)樗緵](méi)名字)。但通過(guò)實(shí)例初始化, 就能夠達(dá)到為匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器的效果,就像這樣: 【荔枝】通過(guò)實(shí)例初始化為匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器 // 荔枝-通過(guò)實(shí)例初始化為匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器 abstract class Base {public Base(int i) { print("Base constructor, i = " + i); }public abstract void f(); } public class AnonymousConstructor {public static Base getBase(int i) {// 通過(guò)實(shí)例初始化, 就能夠達(dá)到為 匿名內(nèi)部類(lèi)創(chuàng)建一個(gè)構(gòu)造器的效果.return new Base(i) {{print("Inside instance initializer");}public void f() {print("In anonymous f(), and i = " + i);}};}public static void main(String[] args) {Base base = getBase(47);base.f();} } /* Base constructor, i = 47 Inside instance initializer In anonymous f(), and i = 47 */ 【補(bǔ)充】在上述荔枝中, 不要求變量i一定是final的。因?yàn)?i 被傳遞給匿名類(lèi)的基類(lèi)構(gòu)造器, 他并不會(huì)在匿名內(nèi)部類(lèi)的內(nèi)部被直接使用;
【荔枝】為內(nèi)部類(lèi)字段進(jìn)行賦值,則方法參數(shù)必須是 final // 荔枝-為內(nèi)部類(lèi)字段進(jìn)行賦值, 則方法參數(shù) 必須是 final public class Parcel10 { // 為內(nèi)部類(lèi)字段進(jìn)行賦值, 則方法參數(shù) 必須是 finalpublic Destination destination(final String dest, final float price) {return new Destination() {private int cost;// 對(duì)每個(gè)對(duì)象進(jìn)行初始化{cost = Math.round(price); // 四舍五入if (cost > 100)System.out.println("Over budget!");}private String label = dest;public String readLabel() {return label;}};}public static void main(String[] args) {Parcel10 p = new Parcel10();Destination d = p.destination("Tasmania", 101.395F);System.out.println(d.readLabel());} } /* Over budget! Tasmania */ 【補(bǔ)充】匿名內(nèi)部類(lèi)與正規(guī)的繼承相比有些受限:因?yàn)槟涿麅?nèi)部類(lèi)既可以擴(kuò)展類(lèi),也可以實(shí)現(xiàn)接口,但不能兩者兼?zhèn)洹H绻麑?shí)現(xiàn)接口,也只能實(shí)現(xiàn)一個(gè)接口;
【10.6.1】在訪(fǎng)工廠方法 【荔枝】基于匿名內(nèi)部類(lèi)的工廠方法 interface Service { void method1(); void method2(); } interface ServiceFactory { Service getService(); } // 荔枝-通過(guò)匿名內(nèi)部類(lèi) 實(shí)現(xiàn)工廠方法模式(經(jīng)典荔枝) class Implementation1 implements Service {private Implementation1() { }public void method1() { print("Implementation1 method1"); }public void method2() { print("Implementation1 method2"); }public static ServiceFactory factory = new ServiceFactory() { // 靜態(tài)匿名內(nèi)部類(lèi)public Service getService() { return new Implementation1(); }}; } class Implementation2 implements Service {private Implementation2() { }public void method1() { print("Implementation2 method1"); }public void method2() { print("Implementation2 method2"); }public static ServiceFactory factory = new ServiceFactory() { // 靜態(tài)匿名內(nèi)部類(lèi)public Service getService() { return new Implementation2(); }}; } public class Factories {public static void serviceConsumer(ServiceFactory fact) {Service s = fact.getService();s.method1();s.method2();}public static void main(String[] args) {serviceConsumer(Implementation1.factory);serviceConsumer(Implementation2.factory);} } /** Output: * Implementation1 method1 * Implementation1 method2 * Implementation2 method1* Implementation2 method2*/// :~ 【荔枝】通過(guò)匿名內(nèi)部類(lèi) 實(shí)現(xiàn)工廠方法模式(經(jīng)典荔枝) interface Game { boolean move(); } interface GameFactory { Game getGame(); } //通過(guò)匿名內(nèi)部類(lèi) 實(shí)現(xiàn)工廠方法模式(經(jīng)典荔枝) class Checkers implements Game {private Checkers() {}private int moves = 0;private static final int MOVES = 3;public boolean move() {print("Checkers move " + moves);return ++moves != MOVES;}public static GameFactory factory = new GameFactory() { // 匿名內(nèi)部類(lèi).public Game getGame() { return new Checkers(); }}; } class Chess implements Game {private Chess() {}private int moves = 0;private static final int MOVES = 4;public boolean move() {print("Chess move " + moves);return ++moves != MOVES;}public static GameFactory factory = new GameFactory() { // 匿名內(nèi)部類(lèi).public Game getGame() { return new Chess(); }}; } public class Games {public static void playGame(GameFactory factory) {Game s = factory.getGame();while (s.move()) ;}public static void main(String[] args) {playGame(Checkers.factory);playGame(Chess.factory);} } /* Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 */ 【10.7】嵌套類(lèi)(靜態(tài)內(nèi)部類(lèi)) 1)靜態(tài)內(nèi)部類(lèi)意味著: 1.1)要?jiǎng)?chuàng)建匿名內(nèi)部類(lèi)的對(duì)象,并不需要其外圍類(lèi)對(duì)象; 1.2)不能從匿名內(nèi)部類(lèi)的對(duì)象中訪(fǎng)問(wèn)非靜態(tài)的外圍類(lèi)對(duì)象; 2)靜態(tài)內(nèi)部類(lèi)與普通內(nèi)部類(lèi)的區(qū)別:普通內(nèi)部類(lèi)的字段與方法, 只能放在類(lèi)的外部層次上, 所以普通內(nèi)部類(lèi)不能有static數(shù)據(jù)和static字段,也不能包含 靜態(tài)內(nèi)部類(lèi)。 但是靜態(tài)內(nèi)部類(lèi)里是可以包含所有這些東西的;
【荔枝】靜態(tài)內(nèi)部類(lèi)可以包含static數(shù)據(jù),static字段和方法,也可以包含普通的字段和方法 // 嵌套類(lèi)(靜態(tài)內(nèi)部類(lèi))的荔枝 public class Parcel11 {// 靜態(tài)內(nèi)部類(lèi)private static class ParcelContents implements Contents {private int i = 11;public int value() { return i; }}// 靜態(tài)內(nèi)部類(lèi)protected static class ParcelDestination implements Destination {private String label; // 普通變量private ParcelDestination(String whereTo) {label = whereTo;}public String readLabel() { // 普通方法return label;}public static void f() { } // 靜態(tài)方法static int x = 10; // 靜態(tài)變量static class AnotherLevel { // 靜態(tài)內(nèi)部類(lèi)( 嵌套類(lèi) )public static void f() { } // 靜態(tài)方法static int x = 10; // 靜態(tài)變量int y = 10; // 普通變量}class A { // 普通內(nèi)部類(lèi)class B {class C { }}}}public static Destination destination(String s) {return new ParcelDestination(s);}public static Contents contents() {return new ParcelContents();}public static void main(String[] args) {Contents c = contents();Destination d = destination("Tasmania");} } 【10.7.1】接口內(nèi)部的類(lèi) 1)正常情況下, 不能在接口內(nèi)部放置任何代碼,但靜態(tài)內(nèi)部類(lèi)可以作為接口的一部分; 2)放置到接口中的任何類(lèi)都默認(rèn)是 public static;
【荔枝】在接口內(nèi)部定義靜態(tài)內(nèi)部類(lèi) // 在接口作用域內(nèi)放置 嵌套類(lèi)(靜態(tài)內(nèi)部類(lèi)) // 接口中的類(lèi) 自動(dòng)是 public 和 static 的. interface ClassInInterface{void howdy();class Test implements ClassInInterface { // 默認(rèn)是 public staticpublic void howdy() {System.out.println("Howdy!");}public static void test() {System.out.println("my name is test.");}public static void main(String[] args) {new Test().howdy(); }} } /* 錯(cuò)誤: 找不到或無(wú)法加載主類(lèi) chapter10.ClassInInterfaceTest$Test */ 【補(bǔ)充】在每個(gè)類(lèi)中都寫(xiě)main方法來(lái)測(cè)試。這樣做有一個(gè)缺點(diǎn): 那就是必須帶著那些已經(jīng)編譯過(guò)的額外代碼。如果這對(duì)你是個(gè)麻煩,那就可以使用匿名內(nèi)部類(lèi)來(lái)放置測(cè)試代碼; //荔枝-使用匿名內(nèi)部類(lèi)來(lái)放置測(cè)試代碼 public class TestBed {public void f() {System.out.println("f()");}public static class Tester {public static void main(String[] args) {TestBed t = new TestBed();t.f();}} } /** Output: f()*/ 【說(shuō)明】這生成了一個(gè)獨(dú)立的類(lèi) TestBed$Tester(要運(yùn)行這個(gè)程序, 執(zhí)行 java TestBed$Tester 即可);可以使用這個(gè)類(lèi)來(lái)做測(cè)試, 但不必再發(fā)布的產(chǎn)品中包含它, 在將產(chǎn)品打包前可以簡(jiǎn)單地刪除 TestBed$Tester.class; 【10.7.2】從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部類(lèi)的成員 1)一個(gè)內(nèi)部類(lèi)被嵌套多少層并不重要:它能透明地訪(fǎng)問(wèn)所有它所嵌入的外圍類(lèi)的所有成員;
【荔枝】從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部類(lèi)的成員 // 荔枝-從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部類(lèi)的成員 class MNA {private void f() {}class A {private void g() {}public class B {// 從多層嵌套類(lèi)中 訪(fǎng)問(wèn)外部類(lèi)的成員.void h() {g(); // 調(diào)用 A.g()f(); // 調(diào)用 MNA.f()}}} }public class MultiNestingAccess {public static void main(String[] args) {MNA mna = new MNA();MNA.A mnaa = mna.new A(); // .new 表達(dá)式提供對(duì)其他外部類(lèi)對(duì)象的引用.MNA.A.B mnaab = mnaa.new B();mnaab.h();} } // /:~ 【10.8】為什么需要內(nèi)部類(lèi)? 1)內(nèi)部類(lèi)最吸引人的原因: 每個(gè)內(nèi)部類(lèi)都能獨(dú)立繼承自一個(gè)(接口的)實(shí)現(xiàn), 所以無(wú)論外圍類(lèi)是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn), 對(duì)于內(nèi)部類(lèi)都沒(méi)有影響; 2)內(nèi)部類(lèi)使得多重繼承的解決方案變得完整。接口解決了多重繼承的部分問(wèn)題, 內(nèi)部類(lèi)有效地實(shí)現(xiàn)了 多重繼承。也就是說(shuō), 內(nèi)部類(lèi)允許繼承多個(gè)非接口類(lèi)型(譯注:類(lèi)或抽象類(lèi));
3)考慮以下情形:必須在一個(gè)類(lèi)中以某種方式實(shí)現(xiàn)兩個(gè)接口。 有兩種實(shí)現(xiàn)方式:使用單一類(lèi), 或者使用內(nèi)部類(lèi); // 荔枝-實(shí)現(xiàn)多重接口的荔枝 // 方式1-使用單一類(lèi) class X implements A, B {}// 方式2-使用內(nèi)部類(lèi), 如下: // 外部類(lèi)本身實(shí)現(xiàn)一個(gè)接口; // 外部類(lèi)的方法返回一個(gè)匿名內(nèi)部類(lèi)(匿名內(nèi)部類(lèi)就是一個(gè)接口類(lèi)型), 以達(dá)到實(shí)現(xiàn)兩個(gè)接口的目的; class Y implements A {B makeB() {// 匿名內(nèi)部類(lèi)return new B() {};} } public class MultiInterfaces {static void takesA(A a) {}static void takesB(B b) {}public static void main(String[] args) {X x = new X();Y y = new Y();takesA(x);takesA(y);takesB(x);takesB(y.makeB()); // this line.(bingo)} } 4)如果擁有的是抽象類(lèi)或具體類(lèi),而不是接口, 那就只能使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承; (干貨——使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承)
【荔枝】使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承 class D {} // 具體類(lèi) abstract class E {} // 抽象類(lèi)// 荔枝-使用內(nèi)部類(lèi)才能實(shí)現(xiàn)多重繼承 class Z extends D {E makeE() {return new E() {};} }public class MultiImplementation {static void takesD(D d) {}static void takesE(E e) {}public static void main(String[] args) {Z z = new Z();takesD(z);takesE(z.makeE());} } 5)內(nèi)部類(lèi)有以下特性: 特性1)內(nèi)部類(lèi)可以有多個(gè)實(shí)例, 每個(gè)實(shí)例都有自己的狀態(tài)信息,并且與其外圍類(lèi)對(duì)象的信息相互獨(dú)立; 特性2)在單個(gè)外圍類(lèi)中, 可以讓多個(gè)內(nèi)部類(lèi)以不同方式實(shí)現(xiàn)同一個(gè)接口,或繼承同一個(gè)類(lèi); 特性3)創(chuàng)建內(nèi)部類(lèi)對(duì)象的時(shí)刻并不依賴(lài)于外圍類(lèi)對(duì)象的創(chuàng)建; 特性4)內(nèi)部類(lèi)并沒(méi)有 is-a 關(guān)系, 他就是一個(gè)獨(dú)立實(shí)體;
【10.8.1】閉包與回調(diào) 1)閉包是一個(gè)可調(diào)用的對(duì)象,他記錄了一些信息,這些信息來(lái)自于創(chuàng)建它的作用域; 2)內(nèi)部類(lèi)是面向?qū)ο蟮拈]包: 因?yàn)閮?nèi)部類(lèi)不僅包含外圍類(lèi)對(duì)象(創(chuàng)建內(nèi)部類(lèi)的作用域)的信息,還自動(dòng)擁有一個(gè)指向指向此外圍類(lèi)對(duì)象的引用,在此作用域內(nèi),內(nèi)部類(lèi)有權(quán)操作所有成員,包括private成員;
【荔枝】通過(guò)內(nèi)部類(lèi)提供閉包功能 // 荔枝-通過(guò)內(nèi)部類(lèi)提供閉包功能 interface Incrementable { void increment(); } // 類(lèi)本身實(shí)現(xiàn)接口 class Callee1 implements Incrementable {private int i = 0;public void increment() { i++; print(i); } }class MyIncrement {public void increment() { print("Other operation"); }static void f(MyIncrement mi) { mi.increment(); } } // 類(lèi)的內(nèi)部類(lèi)實(shí)現(xiàn)接口 class Callee2 extends MyIncrement {private int i = 0;@Overridepublic void increment() {super.increment(); i++; print(i);}// 閉包內(nèi)部類(lèi)private class Closure implements Incrementable {public void increment() {// 指定外部類(lèi)方法,否則你將得到一個(gè)無(wú)限循環(huán).Callee2.this.increment(); // 返回外部類(lèi)對(duì)象的引用(鉤子),利用鉤子調(diào)用外部類(lèi)的方法,稱(chēng)為回調(diào)}}// 返回回調(diào)引用Incrementable getCallbackReference() { 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); // Other operation 1Caller caller1 = new Caller(c1);Caller caller2 = new Caller(c2.getCallbackReference()); // 獲得回調(diào)引用caller1.go(); // 1 caller1.go(); // 2caller2.go(); // Other operation 2caller2.go(); // Other operation 3} } /* Other operation 1 1 2 Other operation 2 Other operation 3 */ 分析1)內(nèi)部類(lèi)Closure 實(shí)現(xiàn)了 Incrementable接口,以提供返回 Callee2的鉤子; 分析2)Caller的構(gòu)造器需要一個(gè) Incrementable 的引用作為參數(shù)(雖然可以在任意時(shí)刻捕獲回調(diào)引用),然后在以后的某個(gè)時(shí)刻,Caller對(duì)象可以使用此引用回調(diào)Callee類(lèi);
【10.9】?jī)?nèi)部類(lèi)的繼承 // 荔枝-內(nèi)部類(lèi)的繼承 class WithInner {class Inner {} }public class InheritInner extends WithInner.Inner {// InheritInner() {} // 這個(gè)無(wú)參構(gòu)造器 無(wú)法編譯,Won't compileInheritInner(WithInner wi) {wi.super();}public static void main(String[] args) {WithInner wi = new WithInner();InheritInner ii = new InheritInner(wi);} } // /:~ 分析1)InheritInner只繼承自?xún)?nèi)部類(lèi),而不是外圍類(lèi); 分析2)當(dāng)要生成一個(gè)構(gòu)造器時(shí),默認(rèn)的構(gòu)造器并不算好,而且不能只是傳遞一個(gè)指向外圍類(lèi)對(duì)象的引用。 分析3)必須在構(gòu)造器內(nèi)使用如下語(yǔ)法: enclosingClassReference.super(); 這樣才提供了必要的引用, 然后程序才能通過(guò)編譯;
【10.10】?jī)?nèi)部類(lèi)可以被覆蓋嗎? 1)內(nèi)部類(lèi)覆蓋:如果創(chuàng)建一個(gè)內(nèi)部類(lèi),然后繼承其外圍類(lèi)并重新定義此內(nèi)部類(lèi)時(shí),會(huì)發(fā)生什么呢? 2)覆蓋內(nèi)部類(lèi)并不起什么作用; // 荔枝-覆蓋內(nèi)部類(lèi)(不起任何作用) class Egg {private Yolk y;protected class Yolk {public Yolk() { print("Egg.Yolk()"); } // 2, 而是調(diào)用這個(gè) Yolk 構(gòu)造方法。}public Egg() {print("New Egg()"); // 1y = new Yolk();} }public class BigEgg extends Egg {// 內(nèi)部類(lèi) BigEgg.Yolk 沒(méi)有覆蓋 內(nèi)部類(lèi) Egg.Yolk public class Yolk {public Yolk() { print("BigEgg.Yolk()"); } // not this one. 并沒(méi)有調(diào)用這個(gè) Yolk 構(gòu)造方法。}public static void main(String[] args) {new BigEgg();} } /* New Egg() Egg.Yolk() */ 3)明確地繼承某個(gè)內(nèi)部類(lèi)是奏效的, 如下: // 荔枝-明確地繼承某個(gè)內(nèi)部類(lèi)是奏效的 class Egg2 {protected class Yolk {public Yolk() { print("Egg2.Yolk()"); } // 1, 3public void f() { print("Egg2.Yolk.f()"); }}private Yolk y = new Yolk();public Egg2() { print("New Egg2()"); } // 2public void insertYolk(Yolk yy) { y = yy; }public void g() { y.f(); } }public class BigEgg2 extends Egg2 {// 內(nèi)部類(lèi) BigEgg2.Yolk 明確繼承繼承 另一個(gè)外部類(lèi)的內(nèi)部類(lèi) Egg2.Yolkpublic class Yolk extends Egg2.Yolk {public Yolk() { print("BigEgg2.Yolk()"); } // 4public void f() { print("BigEgg2.Yolk.f()"); } // 5}public BigEgg2() { insertYolk(new Yolk()); }public static void main(String[] args) {Egg2 e2 = new BigEgg2();e2.g();} } /* Egg2.Yolk() New Egg2() Egg2.Yolk() BigEgg2.Yolk() BigEgg2.Yolk.f() */ 【10.11】局部?jī)?nèi)部類(lèi) 1)介紹: 局部?jī)?nèi)部類(lèi)不能有訪(fǎng)問(wèn)說(shuō)明符,因?yàn)樗皇峭鈬?lèi)的一部分;但是他可以訪(fǎng)問(wèn)當(dāng)前代碼塊內(nèi)的常量,以及此外圍類(lèi)的所有成員; 2)對(duì)局部?jī)?nèi)部類(lèi)與匿名內(nèi)部類(lèi)的創(chuàng)建進(jìn)行了比較,荔枝如下: // 荔枝-局部?jī)?nèi)部類(lèi) // 荔枝-對(duì)局部?jī)?nèi)部類(lèi)與匿名內(nèi)部類(lèi)的創(chuàng)建進(jìn)行了比較 interface Counter { int next(); } public class LocalInnerClass {private int count = 0;Counter getCounter(final String name) {class LocalCounter implements Counter { // 方法域中聲明 局部?jī)?nèi)部類(lèi)public LocalCounter() { print("LocalCounter()"); }public int next() {printnb(name); return count++; // 共同操作 外部類(lèi)的字段}}return new LocalCounter();}Counter getCounter2(final String name) {return new Counter() { // 匿名內(nèi)部類(lèi)完成 與 局部?jī)?nèi)部類(lèi)相同的工作{ print("Counter()"); }public int next() {printnb(name); return count++; // 共同操作 外部類(lèi)的字段}};}public static void main(String[] args) {LocalInnerClass lic = new LocalInnerClass();Counter c1 = lic.getCounter("Local inner "), c2 = lic.getCounter2("Anonymous inner ");for (int i = 0; i < 5; i++)print(c1.next());for (int i = 0; i < 5; i++)print(c2.next());} } /* LocalCounter() Counter() Local inner 0 Local inner 1 Local inner 2 Local inner 3 Local inner 4 Anonymous inner 5 Anonymous inner 6 Anonymous inner 7 Anonymous inner 8 Anonymous inner 9 */ 【補(bǔ)充】為什么有些時(shí)候仍然使用局部?jī)?nèi)部類(lèi),不是已經(jīng)有匿名內(nèi)部類(lèi)了嗎? 理由1)需要一個(gè)已命名的構(gòu)造器,或者需要重載構(gòu)造器,而匿名內(nèi)部類(lèi)只能用于實(shí)例化; 理由2)需要不止一個(gè)該內(nèi)部類(lèi)的對(duì)象;
【10.12】?jī)?nèi)部類(lèi)標(biāo)識(shí)符 1)內(nèi)部類(lèi)生成一個(gè) .class文件以包含他們的 Class 對(duì)象信息; 2)這些類(lèi)文件的命名有嚴(yán)格的規(guī)則: 外圍類(lèi)的名字, 加上 $ , 再加上內(nèi)部類(lèi)的名字; 3)荔枝: LocalInnerClass.java 生成的 .class 文件包括: Counter.class // 接口 LocalInnerClass$1.class // 匿名內(nèi)部類(lèi) LocalInnerClass$1LocalCounter.class // 局部?jī)?nèi)部類(lèi) LocalInnerClass.class // LocalInnerClass類(lèi)
總結(jié)
以上是生活随笔為你收集整理的thinking-in-java(10)内部类的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 帝姬和公主有什么区别 帝姬和公主有区别吗
- 下一篇: Multi-catch paramete