摘要:內(nèi)部類就是這樣一個情況,內(nèi)部類的出現(xiàn)雖然在運行時會被拆分為獨立的臨時類,但是在代碼層面加深了對代碼的理解難度,所以很難說其優(yōu)弊殊勝。
Core Java Volume 1 Key Points chap6 接口和抽象類的概念
接口和抽象類是Java繼承鏈的基礎,其區(qū)別也較為明顯,在Java語言的設計中,允許接口的多實現(xiàn),但不允許抽象類的多繼承,這樣做符合簡潔明了的面向?qū)ο笤O計思路:也就是說類只可以簡單地擁有唯一父模型(抽象類),但是可以擁有多種不同的特征(接口),這樣的設計大大簡化了Java的面向?qū)ο筮壿嫛?/p>
除此之外呢,它們還有這樣的區(qū)別:
接口為了保證其描述特征的特性,只允許描述成員方法的特征(返回值、方法名、參數(shù)),不對成員方法做具體實現(xiàn),而且在接口內(nèi)部不允許使用私有屬性和方法,究其根本,都是因為作為描述特征的接口不應該具有個性化的屬性和方法;而抽象類像類一樣,沒有這樣的限制,但是一般使用缺省的方法來統(tǒng)一定義模型的方法,所以方法體要么是空,要么是通用性較高的默認情況。
另外,在編碼風格上,我們應該盡量給接口起名為形容詞或副詞,以貼近其是對類特征描述的本質(zhì),在JDK中這樣的風格處處可見,比如大多數(shù)的接口會被以able結(jié)尾以說明實現(xiàn)這樣的接口可以獲得某些能力,比如實現(xiàn)Comparable接口可以獲得被比較的能力,進而在對象數(shù)組中可以使用Arrays.sort方法來排序。而抽象類像類一樣使用名詞來定名,另外可以在尾部加上諸如helper,handler來說明其作用。
克隆clone是Object這一通用父類的方法,這個方法是protected類型的,因此在用戶編寫的代碼里是不能直接使用的。這個方法的目的為了實現(xiàn)對象的克隆,理論上講,也就是復制一份完全相同的對象給我們使用。剛剛說了由于它是protected類型的,因此需要在我們使用的需要拷貝的對象的類里重寫這個方法并把權(quán)限設為public的才行,不僅如此,為了類型檢查的原因,我們還需要實現(xiàn)Cloneable這個marker接口(無方法接口)。這樣做顯然很繁瑣,而且由于淺拷貝的問題,還很容易出錯,因為很有可能拷貝出的新對象中某些子對象不是拷貝而仍然是引用。下面是個這樣的例子:
class Email implements Cloneable{ private String info; public Email(String info) { this.info = info; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } class People implements Cloneable { private String name; private Email mail; public String getName() { return name; } public void setName(String name) { this.name = name; } public Email getMail() { return mail; } public void setMail(Email mail) { this.mail = mail; } @Override public String toString() { return "People [name=" + name + ", mail=" + mail.getInfo() + "]"; } @Override public People clone() throws CloneNotSupportedException { // TODO Auto-generated method stub People people = (People) super.clone(); return people; } } public class JustTest { public static void main(String[] args) throws InterruptedException { People people1 = new People(); people1.setName("xiaoming"); people1.setMail(new Email("xm@gmail.com")); People people2 = new People(); try { people2 = (People) people1.clone(); System.out.println(people1); System.out.println(people2); System.out.println("--------------------------------------"); people1.getMail().setInfo("hi@gmail.com"); System.out.println(people1); System.out.println(people2); } catch (Exception e) { e.printStackTrace(); } } }
run:
People [name=xiaoming, mail=xm@gmail.com] People [name=xiaoming, mail=xm@gmail.com] -------------------------------------- People [name=xiaoming, mail=hi@gmail.com] People [name=xiaoming, mail=hi@gmail.com]
這就是淺拷貝帶來的問題,直接使用父類定義的clone就是會有這樣的問題。
所以需要再重寫的clone方法里對這樣的問題進行修改:
@Override public People clone() throws CloneNotSupportedException { // TODO Auto-generated method stub People people = (People) super.clone(); //people.setMail((Email) mail.clone()); return people; }內(nèi)部類
在面向?qū)ο笙到y(tǒng)中,我們的類是對象的模板,接口表示類的特征,每個類擁有自己的成員變量和成員方法,對象擁有自己所屬類的成員變量和成員方法,對象之間互相調(diào)用,通過方法來實現(xiàn)信息溝通并執(zhí)行相應的功能。一切在運行時層面上其實就是這樣,我們在代碼層面可以保持和運行時層面相同的編碼規(guī)則,這樣做可以使得代碼簡潔有力,在編寫和運行的過程中保持一致性。然而事實是任何一門語言都會在代碼層面加入一些特性,注入語法特性,使得編碼看起來更緊湊、編寫更簡單,但是破壞了這種代碼層面和運行時層面的一致性。內(nèi)部類就是這樣一個情況,內(nèi)部類的出現(xiàn)雖然在運行時會被拆分為獨立的臨時類,但是在代碼層面加深了對代碼的理解難度,所以很難說其優(yōu)弊殊勝。
下面是個最簡單的說明其用法的例子:
public class Outer { private String info="hello world"; public class Inner{ public void func(){ System.out.println(info); } } public static void main(String[] args) { Outer outer = new Outer(); Inner inner = outer.new Inner(); inner.func(); } }
這個例子我們可以看出來,這里的內(nèi)部類可以“看做”是Outer的一個成員,所以這樣寫就的內(nèi)部類也叫作成員內(nèi)部類,成員內(nèi)部類可以直接使用外部類的成員和方法,而外部類則需要構(gòu)造內(nèi)部類的對象才能使用內(nèi)部類。之所以說是“看做”,是因為在實際運行時內(nèi)部類會被編譯成一個臨時類而脫離外部類,我們可以試試看:
$ javac Outer.java
編譯后可以得到兩個class文件:Outer.class和Outer$Inner.class,后者就是拆分好了的內(nèi)部類class,所以在運行時可以使其和一般情況一樣。
我們進一步分析其真身:
$ javap Outer Compiled from "Outer.java" public class Outer extends java.lang.Object{ public Outer(); public static void main(java.lang.String[]); static java.lang.String access$000(Outer); } $ javap Outer$Inner Compiled from "Outer.java" public class Outer$Inner extends java.lang.Object{ final Outer this$0; public Outer$Inner(Outer); public void func(); }
我們可以看到內(nèi)部類的臨時獨立生成類的初始化方法中帶有外部類類型的參數(shù),這樣就能夠保證內(nèi)部類可以完整訪問外部類成員變量和成員方法。
那么我們?yōu)槭裁匆褂眠@種看起來就不清不楚的內(nèi)部類呢?我的理解是有些類實際上非常簡單,多帶帶列出對整個系統(tǒng)意義不大,而且和某些類關(guān)系非常大,所以就直接把這個類放入和其關(guān)系大的類之中以形成內(nèi)部類,這樣在代碼層面看起來更加簡潔,但也不影響運行時的正確性。
除了上述的成員內(nèi)部類外,還有局部內(nèi)部類(內(nèi)部類位于方法體內(nèi),這種內(nèi)部類的作用域僅限于方法內(nèi)部)、匿名內(nèi)部類(不對內(nèi)部類進行顯式定義而直接在使用時順帶定義),但是無論是哪一種,其運行時都會被獨立拆分并像一般情況那樣運行。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/65511.html
摘要:所以,在讀的核心技術(shù)的過程中,我記錄下這些所謂的易忽略的問題,這些問題將會持續(xù)更新在我的這個的博客下,也算是激勵自己重新挖掘這些基礎問題的內(nèi)涵。類路徑只是讓能夠通過配置好的全路徑名找到所需的外部類。 開篇Java是一門不那么簡單也不那么復雜的語言,Java里面有很多問題和特性是容易被使用者忽視的,這些問題也許會難住新手,同時也許會是老手不小心跌入的無故之坑,只有精于對基礎的提煉才能最大...
摘要:而并不是父類對象的引用,而只是給編譯器的一個提示性質(zhì)的標志?;蛘咦远x的提示在編譯的時候使用當前子類的父類定義的構(gòu)造器去初始化當前對象。所以,總結(jié)起來,的用法歸為兩種一是可以調(diào)用父類構(gòu)造器,二是可以調(diào)用父類方法。 開篇Java是一門不那么簡單也不那么復雜的語言,Java里面有很多問題和特性是容易被使用者忽視的,這些問題也許會難住新手,同時也許會是老手不小心跌入的無故之坑,只有精于對基礎...
摘要:前言大家好,這里是從零開始學之數(shù)據(jù)類型,本文首發(fā)于公眾號,歡迎前往大家關(guān)注。輸出布爾類型中的布爾類型用表示,它的值有和。若需要可空引用時,布爾類型的值會被裝箱。此時程序會拋出異常最后從零開始學之數(shù)據(jù)類型到這里就結(jié)束了。 前言 大家好,這里是「從零開始學 Kotlin 之『2 』數(shù)據(jù)類型」,本文首發(fā)于公眾號「Binguner」,歡迎前往大家關(guān)注。我會每周分享一些關(guān)于 Android 和...
摘要:老實說,當時一進入世界的大門就暈了,各種規(guī)范概念和英文縮寫詞能把人整的暈暈乎乎。等新的英文縮寫又出現(xiàn)了,一口老血還沒來得及噴出,又重新振作開始新的學習征程。 showImg(http://upload-images.jianshu.io/upload_images/1131767-1c5d16e39435df10.jpg?imageMogr2/auto-orient/strip%7Ci...
閱讀 3661·2021-11-25 09:43
閱讀 3191·2021-10-08 10:04
閱讀 1698·2019-08-26 12:20
閱讀 2127·2019-08-26 12:09
閱讀 683·2019-08-23 18:25
閱讀 3640·2019-08-23 17:54
閱讀 2416·2019-08-23 17:50
閱讀 872·2019-08-23 14:33