真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JAVA中為什么要慎重使用繼承

這篇文章將為大家詳細(xì)講解有關(guān)JAVA中為什么要慎重使用繼承,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的泗陽網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

JAVA中使用到繼承就會(huì)有兩個(gè)無法回避的缺點(diǎn):

  • 打破了封裝性,子類依賴于超類的實(shí)現(xiàn)細(xì)節(jié),和超類耦合。

  • 超類更新后可能會(huì)導(dǎo)致錯(cuò)誤。

繼承打破了封裝性

關(guān)于這一點(diǎn),下面是一個(gè)詳細(xì)的例子(來源于Effective Java第16條)

public class MyHashSet extends HashSet {
 private int addCount = 0;

 public int getAddCount() {
  return addCount;
 }

 @Override
 public boolean add(E e) {
  addCount++;
  return super.add(e);
 }

 @Override
 public boolean addAll(Collection c) {
  addCount += c.size();
  return super.addAll(c);
 }
}

這里自定義了一個(gè)HashSet,重寫了兩個(gè)方法,它和超類唯一的區(qū)別是加入了一個(gè)計(jì)數(shù)器,用來統(tǒng)計(jì)添加過多少個(gè)元素。

寫一個(gè)測(cè)試來測(cè)試這個(gè)新增的功能是否工作:

public class MyHashSetTest {
 private MyHashSet myHashSet = new MyHashSet();

 @Test
 public void test() {
  myHashSet.addAll(Arrays.asList(1,2,3));
  
  System.out.println(myHashSet.getAddCount());
 }
}

運(yùn)行后會(huì)發(fā)現(xiàn),加入了3個(gè)元素之后,計(jì)數(shù)器輸出的值是6。

進(jìn)入到超類中的addAll()方法就會(huì)發(fā)現(xiàn)出錯(cuò)的原因:它內(nèi)部調(diào)用的是add()方法。所以在這個(gè)測(cè)試?yán)?,進(jìn)入子類的addAll()方法時(shí),數(shù)器加3,然后調(diào)用超類的addAll(),超類的addAll()又會(huì)調(diào)用子類的add()三次,這時(shí)計(jì)數(shù)器又會(huì)再加三。

問題的根源

將這種情況抽象一下,可以發(fā)現(xiàn)出錯(cuò)是因?yàn)槌惖目筛采w的方法存在自用性(即超類里可覆蓋的方法調(diào)用了別的可覆蓋的方法),這時(shí)候如果子類覆蓋了其中的一些方法,就可能導(dǎo)致錯(cuò)誤。

JAVA中為什么要慎重使用繼承 

比如上圖這種情況,F(xiàn)ather類里有可覆蓋的方法A和方法B,并且A調(diào)用了B。子類Son重寫了方法B,這時(shí)候如果子類調(diào)用繼承來的方法A,那么方法A調(diào)用的就不再是Father.B(),而是子類中的方法Son.B()。如果程序的正確性依賴于Father.B()中的一些操作,而Son.B()重寫了這些操作,那么就很可能導(dǎo)致錯(cuò)誤產(chǎn)生。

關(guān)鍵在于,子類的寫法很可能從表面上看來沒有問題,但是卻會(huì)出錯(cuò),這就迫使開發(fā)者去了解超類的實(shí)現(xiàn)細(xì)節(jié),從而打破了面向?qū)ο蟮姆庋b性,因?yàn)榉庋b性是要求隱藏實(shí)現(xiàn)細(xì)節(jié)的。更危險(xiǎn)的是,錯(cuò)誤不一定能輕易地被測(cè)出來,如果開發(fā)者不了解超類的實(shí)現(xiàn)細(xì)節(jié)就進(jìn)行重寫,那么可能就埋下了隱患。

超類更新時(shí)可能產(chǎn)生錯(cuò)誤

這一點(diǎn)比較好理解,主要有以下幾種可能:

1、超類更改了已有方法的簽名。會(huì)導(dǎo)致編譯錯(cuò)誤。

2、超類新增了方法:

  • 和子類已有方法的簽名相同但返回類型不同,會(huì)導(dǎo)致編譯錯(cuò)誤。

  • 和子類的已有方法簽名相同,會(huì)導(dǎo)致子類無意中復(fù)寫,回到了第一種情況。

  • 和子類無沖突,但可能會(huì)影響程序的正確性。比如子類中元素加入集合必須要滿足特定條件,這時(shí)候如果超類加入了一個(gè)無需檢測(cè)就可以直接將元素插入的方法,程序的正確性就受到了威脅。

設(shè)計(jì)可繼承的類

設(shè)計(jì)可以用來繼承的類時(shí),應(yīng)該注意:

  • 對(duì)于存在自用性的可覆蓋方法,應(yīng)該用文檔精確描述調(diào)用細(xì)節(jié)。

  • 盡可能少的暴露受保護(hù)成員,否則會(huì)暴露太多實(shí)現(xiàn)細(xì)節(jié)。

  • 構(gòu)造器不應(yīng)該調(diào)用任何可覆蓋的方法。

詳細(xì)解釋下第三點(diǎn)。它實(shí)際上和 繼承打破了封裝性 里討論的問題很相似,假設(shè)有以下代碼:

public class Father {
 public Father() {
  someMethod();
 }

 public void someMethod() {
 }
}
public class Son extends Father {
 private Date date;

 public Son() {
  this.date = new Date();
 }

 @Override
 public void someMethod() {
  System.out.println("Time = " + date.getTime());
 }
}

上述代碼在運(yùn)行測(cè)試時(shí)就會(huì)拋出NullPointerException :

public class SonTest {
 private Son  son = new Son();

 @Test
 public void test() {
  son.someMethod();
 }
}

因?yàn)槌惖臉?gòu)造函數(shù)會(huì)在子類的構(gòu)造函數(shù)之前先運(yùn)行,這里超類的構(gòu)造函數(shù)對(duì)someMethod()有依賴,同時(shí)someMethod()被重寫,所以超類的構(gòu)造函數(shù)里調(diào)用到的將是Son.someMethod(),而這時(shí)候子類還沒被初始化,于是在運(yùn)行到date.getTime()時(shí)便拋出了空指針異常。

因此,如果在超類的構(gòu)造函數(shù)里對(duì)可覆蓋的方法有依賴,那么在繼承時(shí)就可能會(huì)出錯(cuò)。

關(guān)于“JAVA中為什么要慎重使用繼承”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。


網(wǎng)站名稱:JAVA中為什么要慎重使用繼承
文章網(wǎng)址:http://weahome.cn/article/pjpdii.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部