摘要:非內(nèi)部類(lèi)通過(guò)一個(gè)特殊的鏈接到其外圍類(lèi)的對(duì)象,而類(lèi)型的內(nèi)部類(lèi)無(wú)此引用。
用thinkpad打字確實(shí)很爽啊!
Thinking in java系列博文目錄:
Java編程思想學(xué)習(xí)錄(連載之:一切都是對(duì)象)
Java編程思想學(xué)習(xí)錄(連載之:初始化與清理)
Java編程思想學(xué)習(xí)錄(連載之:內(nèi)部類(lèi))
Java編程思想學(xué)習(xí)錄(連載之:異常)
注: 本文首發(fā)于 My 公眾號(hào) CodeSheep ,可 長(zhǎng)按 或 掃描 下面的 小心心 來(lái)訂閱 ↓ ↓ ↓內(nèi)部類(lèi)基本概念
可將一個(gè)類(lèi)的定義置于另一個(gè)類(lèi)定義的內(nèi)部
內(nèi)部類(lèi)允許將邏輯相關(guān)的類(lèi)組織在一起,并控制位于內(nèi)部的類(lèi)的可見(jiàn)性
甚至可將內(nèi)部類(lèi)定義于一個(gè)方法或者任意作用域內(nèi)!
當(dāng)然,內(nèi)部類(lèi) ≠ 組合
內(nèi)部類(lèi)擁有其外圍類(lèi) 所有元素的 訪問(wèn)權(quán)
更有甚,嵌套多層的內(nèi)部類(lèi)能透明地訪問(wèn)所有它所嵌入的外圍類(lèi)的所有成員
一個(gè)典型的例子:利用 Java內(nèi)部類(lèi) 實(shí)現(xiàn)的 迭代器模式
// 接口 ------------------------------------------------------------- public interface Selector { boolean end(); Object current(); void next(); } // 外部類(lèi)(集合類(lèi)) + 內(nèi)部類(lèi)(迭代器類(lèi)) ------------------------------------------------------------- public class Sequence { // 外部類(lèi)(代表一個(gè)集合類(lèi)) 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; } // 迭代器類(lèi):實(shí)現(xiàn)了 Selector接口的 內(nèi)部類(lèi) 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.this 與 .new 的使用場(chǎng)景 .this用于在內(nèi)部類(lèi)中生成對(duì)其外部類(lèi)對(duì)象的引用之時(shí),舉例:
public class DotThis { void f() { print("DotThis.f()"); } public class Inner { // 內(nèi)部類(lèi) public DotThis outer() { // 返回外部類(lèi)對(duì)象的引用 return DotThis.this; // 若直接返回this,那指的便是內(nèi)部類(lèi)自身 } } public Inner inner() { return new Inner(); } public static void main( String[] args ) { DotThis dt = new DotThis(); DotThis.Inner dti = dt.inner(); dti.outer().f(); // 輸出 DotThis.f() } }.new用于直接創(chuàng)建內(nèi)部類(lèi)的對(duì)象之時(shí),距離:
public class DotNew { public class Inner { } // 空內(nèi)部類(lèi) public static void main( String[] args ) { DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner(); //注意此處必須使用外部類(lèi)的對(duì)象,而不能直接 DotNew.Inner dni = new DotNew.Inner() } }嵌套類(lèi)(static類(lèi)型的內(nèi)部類(lèi))嵌套類(lèi)是無(wú)需依賴(lài)其外部類(lèi)的對(duì)象的。非static內(nèi)部類(lèi)通過(guò)一個(gè)特殊的this鏈接到其外圍類(lèi)的對(duì)象,而static類(lèi)型的內(nèi)部類(lèi)無(wú)此this引用。
接口與內(nèi)部類(lèi)有著很有趣的關(guān)系:
放到接口中的任何類(lèi)自動(dòng)都是public且static,即接口中的任何類(lèi)都是嵌套類(lèi),我們甚至可以在接口的內(nèi)部類(lèi)中去實(shí)現(xiàn)其外圍接口,舉例:public interface ClassInInterface { void howdy(); class Test implements ClassInInterface { // 類(lèi)Test默認(rèn)static,所以是嵌套類(lèi) public void howdy() { print("Howdy!"); } public static void main( String[] args ) { new Test().howdy(); } } }在 方法 和 作用域 內(nèi)的內(nèi)部類(lèi)可以稱(chēng)這類(lèi)為 局部?jī)?nèi)部類(lèi)!
方法中定義的內(nèi)部類(lèi)只能在方法內(nèi)被使用,方法之外不可訪問(wèn),舉例:
public class Parcel { // parcel是“包裹”之意 public Destination destination( String s ) { class PDestination implements Destination { // 方法中定義的內(nèi)部類(lèi) private String label; private PDestination( String whereTo ) { label = whereTo; } public String readLabel() { return label; } } return new PDestination( s ); // 只有在方法中才能訪問(wèn)內(nèi)部類(lèi)PDestination } public static void main( String[] args ) { Parcel p = new Parcel(); Destination d = p.destination( "Hello" ); ... } }更進(jìn)一步,可在任意作用域內(nèi)定義內(nèi)部類(lèi),舉例:
public class Parcel { private void internalTracking( boolean b ) { if( b ) { // 局部作用域中定義了內(nèi)部類(lèi),作用域之外不可訪問(wèn)! class TrackingSlip { private String id; TrackingSlip( String s ) { id = s; } String getSlip() { return id; } } } } public void track() { interTracking( true ); } public static void main( String[] args ) { Parcel p = new Parcel(); p.track(); } }匿名內(nèi)部類(lèi)直觀上看,這種內(nèi)部類(lèi)沒(méi)有“名字”,舉例:
public class Parcel { public Contents contents() { return new Contents() { // 此即匿名內(nèi)部類(lèi)!!! private int i = 11; public int value() { return i; } }; // !!!注意這里必須要加分號(hào)!!! } public static void main( String[] args ) { Parcel p = new Parcel(); Contents c = p.contents(); } }若想將外部的參數(shù)傳到匿名內(nèi)部類(lèi)中(典型的如將外部參數(shù)用于對(duì)匿名內(nèi)部類(lèi)中的定義字段進(jìn)行初始化時(shí))使用的話,該參數(shù)必須final,舉例:
public class Parcel { public Destination destination( final String s ) { // final必須! return new Destination() { private String label = s; public String readLabel() { return label; } }; // 分號(hào)必須! } public static void mian( String[] args ) { Parcel p = new Parcel(); Destination d = p.destination("Hello"); } }匿名內(nèi)部類(lèi)中不可能有命名的顯式構(gòu)造器,此時(shí)只能使用實(shí)例初始化的方式來(lái)模仿,舉例(當(dāng)然下面這個(gè)例子還反映了匿名內(nèi)部類(lèi)如何參與繼承):
// 基類(lèi) --------------------------------------------- abstact class Base() { public Base( int i ) { print( "Base ctor, i = " + i ); } public abstract void f(); } //主類(lèi)(其中包含了繼承上面Base的派生匿名內(nèi)部類(lèi)!) ---------------------------------------------- public class AnonymousConstructor { public static Base getBase( int i ) { // 該處參數(shù)無(wú)需final,因?yàn)椴⑽丛谙旅娴膬?nèi)部類(lèi)中直接使用! return new Base(i){ // 匿名內(nèi)部類(lèi) { // 實(shí)例初始化語(yǔ)法!!! print("Inside instance initializer"); } public void f() { print( "In anonymous f()" ); } }; // 分號(hào)必須! } public static void main( String[] args ) { Base base = getBase(47); base.f(); } } // 輸出 ------------------------------------------ Base ctor, i = 47 // 先基類(lèi) Inside instance initializer // 再打印派生類(lèi) In anonymous f()匿名內(nèi)部類(lèi) + 工廠模式 = 更加簡(jiǎn)潔易懂:
// Service接口 --------------------------------------------------- interface Service { void method1(); void method2(); } // ServiceFactory接口 --------------------------------------------------- interface ServiceFactory { Service getService(); } // Service接口的實(shí)現(xiàn) --------------------------------------------------- class Implementation1 implements Service { private Implementation1() {} // 構(gòu)造函數(shù)私有 public void method1() { print("Implementation1 method1"); } public void method2() { print("Implementation1 method2"); } public static ServiceFactory factory = new ServiceFactory() { public Service getService() { return new Implementation1(); } }; // 分號(hào)必須!!! } class Implementation2 implements Service { private Implementation2() {} public void method1() { print("Implementation2 method1"); } public void method2() { print("Implementation2 method2"); } public static ServiceFactory factory = new ServiceFactory() { public Service getService() { return new Implementation2(); } }; // 分號(hào)必須!!! } // 客戶端代碼 ---------------------------------------------------- public class Factories { public static void serviceConsumer( ServiceFactory fact ) { Service s = fact.getService(); s.method1(); s.method2(); } public static void main( String[] args ) { serviceComsumer( Implementation1.factory ); serviceComsumer( Implementation2.factory ); } }總結(jié):為什么需要內(nèi)部類(lèi)內(nèi)部類(lèi)可以獨(dú)立地繼承自一個(gè)接口或者類(lèi)而無(wú)需關(guān)注其外圍類(lèi)的實(shí)現(xiàn),這使得擴(kuò)展類(lèi)或者接口更加靈活,控制的粒度也可以更細(xì)!
注意Java中還有一個(gè)細(xì)節(jié):雖然Java中一個(gè)接口可以繼承多個(gè)接口,但是一個(gè)類(lèi)是不能繼承多個(gè)類(lèi)的!要想完成該特性,此時(shí)除了使用內(nèi)部類(lèi)來(lái)“擴(kuò)充多重繼承機(jī)制”,你可能別無(wú)選擇,舉例:
class D { } // 普通類(lèi) abstract class E { } // 抽象類(lèi) class Z extend D { // 外圍類(lèi)顯式地完成一部分繼承 E makeE() { return new E() { }; // 內(nèi)部類(lèi)隱式地完成一部分繼承 } } 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() ); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/68291.html
摘要:注本文首發(fā)于公眾號(hào),可長(zhǎng)按或掃描下面的小心心來(lái)訂閱關(guān)于構(gòu)造器與初始化無(wú)參構(gòu)造器默認(rèn)構(gòu)造器自己未寫(xiě)編譯器幫忙自動(dòng)創(chuàng)建的若自行定義了構(gòu)造器無(wú)論參數(shù)有否,編譯器便停止默認(rèn)創(chuàng)建動(dòng)作類(lèi)里的對(duì)象引用默認(rèn)初始化為,基本類(lèi)型初始化為構(gòu)造器也是類(lèi)的靜態(tài)方法四 showImg(https://segmentfault.com/img/remote/1460000015723687); 注: 本文首發(fā)于 ...
摘要:系列博文目錄編程思想學(xué)習(xí)錄連載之一切都是對(duì)象編程思想學(xué)習(xí)錄連載之初始化與清理編程思想學(xué)習(xí)錄連載之內(nèi)部類(lèi)編程思想學(xué)習(xí)錄連載之異常本篇文章將講述關(guān)于異常的相關(guān)知識(shí)注本文首發(fā)于公眾號(hào),可長(zhǎng)按或掃描下面的小心心來(lái)訂閱基本概念使用異常來(lái)提供一致性的錯(cuò) showImg(https://segmentfault.com/img/remote/1460000013228854); Thinking ...
摘要:前端技術(shù)棧還是非常龐大的,為了能夠借助已經(jīng)存在的輪子來(lái)造出一輛車(chē),所以我選擇了進(jìn)行實(shí)踐。狀態(tài)的管理的狀態(tài)管理依靠完成,用其來(lái)管理的所有組件狀態(tài)。私有云客戶端打造主頁(yè)面首先是主頁(yè)面,可以打開(kāi)任何一個(gè)云主機(jī)系統(tǒng)的頁(yè)面看,基本類(lèi)似。 showImg(https://segmentfault.com/img/remote/1460000013930354); 【利用K8S技術(shù)棧打造個(gè)人私有...
摘要:前端技術(shù)棧還是非常龐大的,為了能夠借助已經(jīng)存在的輪子來(lái)造出一輛車(chē),所以我選擇了進(jìn)行實(shí)踐。狀態(tài)的管理的狀態(tài)管理依靠完成,用其來(lái)管理的所有組件狀態(tài)。私有云客戶端打造主頁(yè)面首先是主頁(yè)面,可以打開(kāi)任何一個(gè)云主機(jī)系統(tǒng)的頁(yè)面看,基本類(lèi)似。 showImg(https://segmentfault.com/img/remote/1460000013930354); 【利用K8S技術(shù)棧打造個(gè)人私有...
摘要:我稱(chēng)之為輕量級(jí)函數(shù)式編程。序眾所周知,我是一個(gè)函數(shù)式編程迷。函數(shù)式編程有很多種定義。本書(shū)是你開(kāi)啟函數(shù)式編程旅途的絕佳起點(diǎn)。事實(shí)上,已經(jīng)有很多從頭到尾正確的方式介紹函數(shù)式編程的書(shū)了。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 譯者團(tuán)隊(duì)(排名不分先后):阿希、blueken、brucecham、...
閱讀 3119·2023-04-25 16:50
閱讀 922·2021-11-25 09:43
閱讀 3534·2021-09-26 10:11
閱讀 2530·2019-08-26 13:28
閱讀 2543·2019-08-26 13:23
閱讀 2436·2019-08-26 11:53
閱讀 3578·2019-08-23 18:19
閱讀 3002·2019-08-23 16:27