摘要:內(nèi)部類就是這樣一個(gè)情況,內(nèi)部類的出現(xiàn)雖然在運(yùn)行時(shí)會(huì)被拆分為獨(dú)立的臨時(shí)類,但是在代碼層面加深了對(duì)代碼的理解難度,所以很難說(shuō)其優(yōu)弊殊勝。
Core Java Volume 1 Key Points chap6 接口和抽象類的概念
接口和抽象類是Java繼承鏈的基礎(chǔ),其區(qū)別也較為明顯,在Java語(yǔ)言的設(shè)計(jì)中,允許接口的多實(shí)現(xiàn),但不允許抽象類的多繼承,這樣做符合簡(jiǎn)潔明了的面向?qū)ο笤O(shè)計(jì)思路:也就是說(shuō)類只可以簡(jiǎn)單地?fù)碛形ㄒ桓改P停ǔ橄箢悾强梢該碛卸喾N不同的特征(接口),這樣的設(shè)計(jì)大大簡(jiǎn)化了Java的面向?qū)ο筮壿嫛?/p>
除此之外呢,它們還有這樣的區(qū)別:
接口為了保證其描述特征的特性,只允許描述成員方法的特征(返回值、方法名、參數(shù)),不對(duì)成員方法做具體實(shí)現(xiàn),而且在接口內(nèi)部不允許使用私有屬性和方法,究其根本,都是因?yàn)樽鳛槊枋鎏卣鞯慕涌诓粦?yīng)該具有個(gè)性化的屬性和方法;而抽象類像類一樣,沒(méi)有這樣的限制,但是一般使用缺省的方法來(lái)統(tǒng)一定義模型的方法,所以方法體要么是空,要么是通用性較高的默認(rèn)情況。
另外,在編碼風(fēng)格上,我們應(yīng)該盡量給接口起名為形容詞或副詞,以貼近其是對(duì)類特征描述的本質(zhì),在JDK中這樣的風(fēng)格處處可見(jiàn),比如大多數(shù)的接口會(huì)被以able結(jié)尾以說(shuō)明實(shí)現(xiàn)這樣的接口可以獲得某些能力,比如實(shí)現(xiàn)Comparable接口可以獲得被比較的能力,進(jìn)而在對(duì)象數(shù)組中可以使用Arrays.sort方法來(lái)排序。而抽象類像類一樣使用名詞來(lái)定名,另外可以在尾部加上諸如helper,handler來(lái)說(shuō)明其作用。
克隆clone是Object這一通用父類的方法,這個(gè)方法是protected類型的,因此在用戶編寫的代碼里是不能直接使用的。這個(gè)方法的目的為了實(shí)現(xiàn)對(duì)象的克隆,理論上講,也就是復(fù)制一份完全相同的對(duì)象給我們使用。剛剛說(shuō)了由于它是protected類型的,因此需要在我們使用的需要拷貝的對(duì)象的類里重寫這個(gè)方法并把權(quán)限設(shè)為public的才行,不僅如此,為了類型檢查的原因,我們還需要實(shí)現(xiàn)Cloneable這個(gè)marker接口(無(wú)方法接口)。這樣做顯然很繁瑣,而且由于淺拷貝的問(wèn)題,還很容易出錯(cuò),因?yàn)楹苡锌赡芸截惓龅男聦?duì)象中某些子對(duì)象不是拷貝而仍然是引用。下面是個(gè)這樣的例子:
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]
這就是淺拷貝帶來(lái)的問(wèn)題,直接使用父類定義的clone就是會(huì)有這樣的問(wèn)題。
所以需要再重寫的clone方法里對(duì)這樣的問(wèn)題進(jìn)行修改:
@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)中,我們的類是對(duì)象的模板,接口表示類的特征,每個(gè)類擁有自己的成員變量和成員方法,對(duì)象擁有自己所屬類的成員變量和成員方法,對(duì)象之間互相調(diào)用,通過(guò)方法來(lái)實(shí)現(xiàn)信息溝通并執(zhí)行相應(yīng)的功能。一切在運(yùn)行時(shí)層面上其實(shí)就是這樣,我們?cè)诖a層面可以保持和運(yùn)行時(shí)層面相同的編碼規(guī)則,這樣做可以使得代碼簡(jiǎn)潔有力,在編寫和運(yùn)行的過(guò)程中保持一致性。然而事實(shí)是任何一門語(yǔ)言都會(huì)在代碼層面加入一些特性,注入語(yǔ)法特性,使得編碼看起來(lái)更緊湊、編寫更簡(jiǎn)單,但是破壞了這種代碼層面和運(yùn)行時(shí)層面的一致性。內(nèi)部類就是這樣一個(gè)情況,內(nèi)部類的出現(xiàn)雖然在運(yùn)行時(shí)會(huì)被拆分為獨(dú)立的臨時(shí)類,但是在代碼層面加深了對(duì)代碼的理解難度,所以很難說(shuō)其優(yōu)弊殊勝。
下面是個(gè)最簡(jiǎn)單的說(shuō)明其用法的例子:
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(); } }
這個(gè)例子我們可以看出來(lái),這里的內(nèi)部類可以“看做”是Outer的一個(gè)成員,所以這樣寫就的內(nèi)部類也叫作成員內(nèi)部類,成員內(nèi)部類可以直接使用外部類的成員和方法,而外部類則需要構(gòu)造內(nèi)部類的對(duì)象才能使用內(nèi)部類。之所以說(shuō)是“看做”,是因?yàn)樵趯?shí)際運(yùn)行時(shí)內(nèi)部類會(huì)被編譯成一個(gè)臨時(shí)類而脫離外部類,我們可以試試看:
$ javac Outer.java
編譯后可以得到兩個(gè)class文件:Outer.class和Outer$Inner.class,后者就是拆分好了的內(nèi)部類class,所以在運(yùn)行時(shí)可以使其和一般情況一樣。
我們進(jìn)一步分析其真身:
$ 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í)獨(dú)立生成類的初始化方法中帶有外部類類型的參數(shù),這樣就能夠保證內(nèi)部類可以完整訪問(wèn)外部類成員變量和成員方法。
那么我們?yōu)槭裁匆褂眠@種看起來(lái)就不清不楚的內(nèi)部類呢?我的理解是有些類實(shí)際上非常簡(jiǎn)單,多帶帶列出對(duì)整個(gè)系統(tǒng)意義不大,而且和某些類關(guān)系非常大,所以就直接把這個(gè)類放入和其關(guān)系大的類之中以形成內(nèi)部類,這樣在代碼層面看起來(lái)更加簡(jiǎn)潔,但也不影響運(yùn)行時(shí)的正確性。
除了上述的成員內(nèi)部類外,還有局部?jī)?nèi)部類(內(nèi)部類位于方法體內(nèi),這種內(nèi)部類的作用域僅限于方法內(nèi)部)、匿名內(nèi)部類(不對(duì)內(nèi)部類進(jìn)行顯式定義而直接在使用時(shí)順帶定義),但是無(wú)論是哪一種,其運(yùn)行時(shí)都會(huì)被獨(dú)立拆分并像一般情況那樣運(yùn)行。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65511.html
摘要:所以,在讀的核心技術(shù)的過(guò)程中,我記錄下這些所謂的易忽略的問(wèn)題,這些問(wèn)題將會(huì)持續(xù)更新在我的這個(gè)的博客下,也算是激勵(lì)自己重新挖掘這些基礎(chǔ)問(wèn)題的內(nèi)涵。類路徑只是讓能夠通過(guò)配置好的全路徑名找到所需的外部類。 開(kāi)篇Java是一門不那么簡(jiǎn)單也不那么復(fù)雜的語(yǔ)言,Java里面有很多問(wèn)題和特性是容易被使用者忽視的,這些問(wèn)題也許會(huì)難住新手,同時(shí)也許會(huì)是老手不小心跌入的無(wú)故之坑,只有精于對(duì)基礎(chǔ)的提煉才能最大...
摘要:而并不是父類對(duì)象的引用,而只是給編譯器的一個(gè)提示性質(zhì)的標(biāo)志。或者自定義的提示在編譯的時(shí)候使用當(dāng)前子類的父類定義的構(gòu)造器去初始化當(dāng)前對(duì)象。所以,總結(jié)起來(lái),的用法歸為兩種一是可以調(diào)用父類構(gòu)造器,二是可以調(diào)用父類方法。 開(kāi)篇Java是一門不那么簡(jiǎn)單也不那么復(fù)雜的語(yǔ)言,Java里面有很多問(wèn)題和特性是容易被使用者忽視的,這些問(wèn)題也許會(huì)難住新手,同時(shí)也許會(huì)是老手不小心跌入的無(wú)故之坑,只有精于對(duì)基礎(chǔ)...
摘要:前言大家好,這里是從零開(kāi)始學(xué)之?dāng)?shù)據(jù)類型,本文首發(fā)于公眾號(hào),歡迎前往大家關(guān)注。輸出布爾類型中的布爾類型用表示,它的值有和。若需要可空引用時(shí),布爾類型的值會(huì)被裝箱。此時(shí)程序會(huì)拋出異常最后從零開(kāi)始學(xué)之?dāng)?shù)據(jù)類型到這里就結(jié)束了。 前言 大家好,這里是「從零開(kāi)始學(xué) Kotlin 之『2 』數(shù)據(jù)類型」,本文首發(fā)于公眾號(hào)「Binguner」,歡迎前往大家關(guān)注。我會(huì)每周分享一些關(guān)于 Android 和...
摘要:老實(shí)說(shuō),當(dāng)時(shí)一進(jìn)入世界的大門就暈了,各種規(guī)范概念和英文縮寫詞能把人整的暈暈乎乎。等新的英文縮寫又出現(xiàn)了,一口老血還沒(méi)來(lái)得及噴出,又重新振作開(kāi)始新的學(xué)習(xí)征程。 showImg(http://upload-images.jianshu.io/upload_images/1131767-1c5d16e39435df10.jpg?imageMogr2/auto-orient/strip%7Ci...
閱讀 3553·2021-11-25 09:43
閱讀 3134·2021-10-08 10:04
閱讀 1625·2019-08-26 12:20
閱讀 2053·2019-08-26 12:09
閱讀 595·2019-08-23 18:25
閱讀 3573·2019-08-23 17:54
閱讀 2322·2019-08-23 17:50
閱讀 803·2019-08-23 14:33