學習 Java程式設計思想 Thinking in Java 第十章:內部類
前言
和我一起讀書書,一起喵喵喵喵喵~
在讀 《Java程式設計思想 Thinking in Java》 這本書的時候,會有很多示例程式碼。為了鞏固和實踐,所以將書上的程式碼都寫上一遍(其實是逼自己寫程式碼)。目前我已經讀到第十章:內部類 了,程式碼也會從這裡開始寫。前面的程式碼就算了,不補了,Just do it!
10.5 在方法和作用域內的內部類
先寫個介面Destination:
package com.innerClass;
public interface Destination {
String readLabel();
}
接下來就寫,在方法的作用域中建立一個完整的類。這被叫做區域性內部類
package com.innerClass; 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"); } }
下面展示,如何在任意作用域內嵌入一個內部類:
package com.innerClass; 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(); } //試想一下上面這兩句話,寫到這裡可不可以呢? } public void track(){ internalTracking(true); } public static void main(String[] args) { Parcel6 p = new Parcel6(); p.track();; } }
回答程式碼中的問題,答案是不可以哦,因為那裡是 if的作用域外,超出了TrackingSlip的作用域了!
10.6 匿名內部類
先寫個介面,做鋪墊啊
package com.innerClass;
public interface Contents {
int value();
}
馬上寫一個匿名內部類啊
package com.innerClass;
public class Parcel7 {
public Contents contents(){
return new Contents() {
private int i = 11;
@Override
public int value() {
return i;
}
};
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
在contents方法中,return的那個類,沒有名字,看吧,是不是很奇怪。
在return一個new的Contents的時候,彷彿聽見一個聲音,說:“等等,我想在這裡插入一個內的定義”。結果就成這個樣子了。
這就是匿名內部類啊!!!
對這個奇怪的語法正兒八經的總結一下就是:“建立一個繼承自Contents的匿名內部類的物件。通過new表示式返回的引用被自動向上轉型為對Contents的引用。”
上述匿名內部類的語法是下述形式的簡化形式:
package com.innerClass;
public class Parcel7b {
class MyContents implements Contents{
private int i = 11;
@Override
public int value() {
return i;
}
}
public Contents contents(){
return new MyContents();
}
public static void main(String[] args) {
Parcel7b p = new Parcel7b();
Contents c = p.contents();
}
}
有沒有覺得第一種書寫方式更裝逼一點呢!
咦?咦咦咦?
我發現上面那個匿名內部類使用了預設構造器來生成Contents,但是如果基類需要一個有引數的構造器,就像下面這樣,改怎麼辦呢?
package com.innerClass;
public class Parcel8 {
public Wrapping wrapping(int x){
return new Wrapping(x){
@Override
public int value() {
return super.value() * 47;
}
};
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);
}
}
Wrapping這個類我該怎樣寫,才能正確的被Parcel8使用呢?
很簡單!只需要傳遞合適的引數給基類的構造器即可,就像這樣:
package com.innerClass;
public class Wrapping {
private int i;
public Wrapping(int x){
i = x;
}
public int value(){
return i;
}
}
雖然Wrapping只是一個具有具體實現的普通類,但還是被其匯出類當作公共“介面”來使用!
如果在匿名類中定義欄位時,還要對其執行初始化操作,該咋寫呢?就該像下面這樣寫呀:
package com.innerClass;
public class Parcel9 {
public Destination destination(final String dest){
return new Destination() {
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
注意到了嗎?用到了關鍵字final哦,如果定義一個匿名內部類,並且希望它使用一個在其外部定義的物件時,那麼編譯器就會要求其引數是final的。
實現一個為匿名內部類建立一個構造器的效果:
package com.innerClass;
public abstract class Base {
public Base(int i){
System.out.println("Base constructor, i = "+i);
}
public abstract void f();
}
package com.innerClass;
import com.sun.org.apache.xpath.internal.SourceTree;
public class AnonymousConstructor {
public static Base getBase(int i){
return new Base(i) {
@Override
public void f() {}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
這個例子中呢,變數i,不要求是final的。因為 i 被傳遞給匿名類的基類的構造器,並沒有在匿名類內部直接使用。
帶例項初始化的“parcel”形式。
package com.innerClass;
public class Parcel10 {
public Destination destination(final String dest, final float price){
return new Destination() {
private int cost;
{
cost = Math.round(price);
if(cost > 100){
System.out.println("Over budget");
}
}
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel10 p = new Parcel10();
Destination d = p.destination("Tasmania", 101.395F);
}
}
10.6.1 再訪工廠方法
使用匿名內部類改造 interfaces/Factories.java 示例:
package com.innerClass;
public interface Service {
void method1();
void method2();
}
package com.innerClass;
public interface ServiceFactory {
Service getService();
}
package com.innerClass;
public class Implementation1 implements Service{
private Implementation1(){}
@Override
public void method1() {
System.out.println("Implementation1 method1");
}
@Override
public void method2() {
System.out.println("Implementation1 method2");
}
public static ServiceFactory factory = new ServiceFactory() {
@Override
public Service getService() {
return new Implementation1();
}
};
}
package com.innerClass;
public class Implementation2 implements Service{
private Implementation2(){}
@Override
public void method1() {
System.out.println("Implementation2 method1");
}
@Override
public void method2() {
System.out.println("Implementation2 method2");
}
public static ServiceFactory factory = new ServiceFactory() {
@Override
public Service getService() {
return new Implementation2();
}
};
}
package com.innerClass;
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);
}
}
改造 interfaces/Games.java 示例:
package com.innerClass.games;
public interface Game {
boolean move();
}
package com.innerClass.games;
public interface GameFactory {
Game getGame();
}
package com.innerClass.games;
public class Checkers implements Game{
private Checkers(){}
private int moves = 0;
private static final int MOVES = 3;
@Override
public boolean move() {
System.out.println("Checkers move " + moves);
return ++moves != MOVES;
}
public static GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new Checkers();
}
};
}
package com.innerClass.games;
public class Chess implements Game{
private Chess(){}
private int moves = 0;
private static final int MOVES = 4;
@Override
public boolean move() {
System.out.println("Chess move "+ moves);
return ++moves != MOVES;
}
public static GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new Chess();
}
};
}
package com.innerClass.games;
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);
}
}
10.7 巢狀類
相關推薦
學習 Java程式設計思想 Thinking in Java 第十章:內部類
前言 和我一起讀書書,一起喵喵喵喵喵~ 在讀 《Java程式設計思想 Thinking in Java》 這本書的時候,會有很多示例程式碼。為了鞏固和實踐,所以將書上的程式碼都寫上一遍(其實是逼自己寫程式碼)。目前我已經讀到第十章:內部類 了,程式碼也會從這裡開
Java程式設計思想(二)第14章-型別資訊
目錄: 1. RTTI(Runtime Type Identification)執行階段型別識別 1.1 用途: 為了確定基類指標實際指向的子類的具體型別。——《C++ Primer Plus》 1.2 工作原理: 通過型別轉換運算子回答“是否可以
Java程式設計思想(三)第15章-泛型
目錄: 泛型(generics)的概念是Java SE5的重大變化之一。泛型實現了引數化型別(parameterized types)的概念,使程式碼可以應用於多種型別。“泛型”這個術語的意思是:“適用於許多許多的型別”。 1 泛型方法 泛型方法與其所在的類
Java程式設計思想(六)第19章-列舉型別
目錄: 19.4 values()的神祕之處 通過反編譯列舉類,values()是由編譯器新增的static()方法。編譯器將列舉類(enum)標記為final類,所以enum類無法被繼承。 19.5 實現而非繼承 所有的enum類都繼承自java.lan
Java程式設計思想(七)第20章-註解
目錄: 註解(也被稱為元資料)為我們在程式碼中新增資訊提供了一種形式化的方法,使我們可以在稍後某個時刻非常方便地使用這些資料。 1 基本語法 被註解的方法與其他的方法沒有區別。註解可以
Java程式設計思想(五)第18章-Java IO系統
目錄: 1 File類 File(檔案)類這個名字有一定的誤導性;我們可能會認為它指代的是檔案,實際上卻並非如此。它既能代表一個特定檔案的名稱,又能代表一個目錄下的一組檔案的名稱。實際上,FilePath(檔案路徑)對這個類來說是更好的名字。 如果它指的
《Java程式設計思想》筆記之第六章——訪問許可權控制
本文只摘錄很少一部分,作文筆記。訪問控制(或隱藏具體實現)與“最初的實現並不恰當”有關當編寫一個Java原始碼檔案時,此檔案通被稱為編譯單元(有時也被稱為轉譯單元)。每個編譯單元都必須有一個字尾名為.java,而編譯單元內測可以有一個public類,該類的名稱必須與檔名稱相同
java 程式設計思想課後題(第四章)
練習1: public class twoSum { public static void main(String[] args){ for(int i = 1;i <= 100;i ++){ System.out.pr
Java程式設計思想閱讀筆記(第10章內部類)
內部類 內部類是指在一個外部類的內部再定義一個類。內部類作為外部類的一個成員,並且依附於外部類而存在的 可以將一個類的定義放在另一個類定義內部,這就是內部類 內部類自動擁有對包裹它的基類所有成員的訪問許可權 內部類可為靜態,可用protected和priva
“全棧2019”Java第九十章:內部類可以向上或向下轉型嗎?
難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 IntelliJ IDEA v2018.3 文章原文連結 “全棧2019”Java第九十章:內部類可以向上或向下轉型嗎? 下一章 “全棧2019”Java第九十一章:內部類具
Python程式設計從入門到實踐第十章:檔案和異常
檔案和異常 從檔案中讀取資料 1.函式open() 要以任何方式使用檔案,都得先開啟檔案,這樣才能訪問它. 接受一個引數:要開啟檔案的名稱. 返回一個表示檔案的物件.Python將這個物件儲存在後面要使用
第十章:內核同步方法
font 長時間 加鎖 height 讀取數據 簡單 允許 接口 優先 10.1 原子操作 同步方法中的原子操作是其他同步方法的基石; 原子操作可以保證指令以原子的方式執行------執行過程不被打斷。 原子操作可以把讀取和增加變量的行為包含在一個單步中執行,從而防止
[隨筆][Java][讀書筆記][thinking in java][第十四章 類型信息]
found 構造 att main 數組 test 第一個 eating urn 主要理解如何在運行時獲取類型信息。主要有兩種方式:一是RTTI,假定我們在編譯時已經知道了所有的類型;二是反射機制,允許在運行時發現和使用類的信息。 14.1 為什麽需要RTTI 一個多
[隨筆][Java][讀書筆記][thinking in java][第十章 內部類]
10.6 效果 getc tps 啟動 implement bool 多個 tina 可以將一個類定義在另一個類的內部,這就是內部類。 10.1 創建內部類 public class Parcell { class Contents { priv
[隨筆][Java][讀書筆記][thinking in java][第十八章 Java I/O系統]
參數 數列 == tar 目錄樹 返回 匿名類 string 筆記 18.1 File類 目錄列表器。兩種方法使用File對象查看一個目錄列表。 import java.util.regex.*; import java.io.*; import java.util.*
使用ant編譯Java程式設計思想出現時 java.lang.UnsupportedClassVersionError: Bad version number in .class問題
問題詳情如下圖所示 解決方法是將TIJ4/code/build.xml中的net/build.xml刪除即可編譯成功,過段時間後確定是當前所用的javassist.jar與jdk 1.5.0_22 不相容造成這個原因,之前javaassisst.jar使用的是3.16.1版本,經測試確
201711671208 《Java程式設計》之執行緒 第十一週學習計劃
使用Thread類的子類建立執行緒寫法,如: public class SpeakElephant extends Thread { public void run(){ ...} } SpeakElephant xxx; //宣告 xxx=new SpeakEl
Java程式設計思想之讀書筆記系列十一 --- 第十三章 --- 字串
String物件是不可變的,具有隻讀特性 預先指定StringBuilder的大小可以避免多次重新分配緩衝(那麼:如果超出預先指定的大小,會出現什麼情況呢?) 重寫自定義類的toString()方法
Java 記憶體分配——Thinking in Java 4th 讀書筆記
做開發多年,一直忙於專案,從沒好好的整理知識,從現在開始,儘量每週多抽時間整理知識,分享在部落格,在接下來的部落格中,我將為大家分享我讀《Java程式設計思想4th》英文版讀書筆記,一來便於知識的梳理,二來分享給需要的朋友,評價很高的一本書,推薦大家閱讀,因為書的邊幅比較長,如果不想閱讀整本書歡迎來
java程式設計的邏輯讀書筆記——第五章
類的擴充套件 介面和抽象類 interface 宣告介面 implements實現介面 介面約定的是功能,而不是具體實現 介面中方法的預設修飾符為public abstract 介面中變數的預設修飾符為public static final 介面