2012-11-13 19 views
1

我們有兩個類(一個父類和一個子類)。都使用私有變量來存儲值,但父母不應該提供setter(x和y與構造函數一起給出,它們是某種不可變的)。 B應該用x和y的setter擴展A.有沒有一種常見的方式來做到這一點?Java繼承 - 僅在子類型中設置者

class A{ 
    private int x; 
    private int y; 

    A(int x, int y){ 
     this.x = x; 
     this.y = y; 
    } 

} 

class B extends A{ 

    public void setx(int x){ 
     this.x = x; 
    } 

    //same for y 
} 

的幾點思考

  • 變量應該是私有
  • x和家長的y的爲不可變的
  • B必須提供一個公共的setter
+4

如果'A'的合同是不可變的,而'B'擴展了'A',那麼'B' **必須是不可變的。否則,你打破了「是一個」的承諾。代碼可以對'B'對象具有'A'類型的引用,並且儘管'A'是不可變的,發現對象發生了變化。不好。 :-) –

+2

我認爲這裏有一個設計問題。你所說的是x和y是最終的(不可變的),所以改變它們有什麼意義呢?如果你想在一個子類中改變它們,這甚至是最糟糕的:如果一個子類需要改變父類的不可變值,那就不是合適的子類。 –

+0

@NaN:我想你只是用一種讓它看起來比實際更復雜的方式來表達它。看看這些評論,你*不需要*''和'y'在'A'中是不可變的,你只需要'A'不要有任何setter。這裏有一個區別(根據「A」提供的合同)。如果'B'可以修改從'A'繼承的'x'和'y',那麼M​​eNoMore的答案是正確的。 –

回答

3

如果你想要的變量是不變的,那麼它應該是

class B extends A{ 

    public B(int x, int y){ 
      super(x, y); 
    } 
} 

目前在A中的變量x和y都不是一成不變的。爲了讓他們一成不變然後用final

它們之前這是你可以因爲它們是私人爲x和y的唯一途徑。如果你想要setter,那麼你將不得不使變量受到保護。

就我個人而言,我是不變性的忠實粉絲,所以會這樣做而不是setter - 創建對象通常很便宜。

1

你可以用」 t有一個私有成員變量和沒有方法(這裏的方法我的意思也是構造函數)設置它(嗯,技術上你可以,但它doe沒有意義)。如果您希望您的變量可以從派生類中設置,則必須對其進行保護。

編輯:你可以,但是,定義在基類受保護的「幫手」二傳手和派生類中的公共setter方法調用該受保護的幫助二傳手。

SECOND編輯:另一種可能性是定義在基類的抽象getter和實施吸氣,設定器,以及私有字段,在派生類(模板模式)。

+1

有一種設置方法:構造函數。完全正常的只有由構造函數設置的字段。無論如何,這是*評論*,而不是答案。 –

+0

他問他如何在派生類中設置私有變量。我的答案是:這是不可能的。所以它*是一個答案。 – JohnB

+0

@約翰:不,你所說的只是「讓他們受到保護。」這個問題比這更復雜。 –

3

聲明變量protected在基類和子類寫getter和setter。

+0

再次閱讀這個問題:*「父母的x和y必須是不可變的」*在派生類中提供setter使它們可變。 –

+1

@ T.J.Crowder:Po寫道:「某種不可變的」,PO也寫道:「帶有x和y的setters」,我想他的意思是他們應該是不可變的,但應該在派生類中變化。 – CloudyMarble

+0

@MeNoMore是的!在A中它們是不可變的,在B中它們是可變的! – NaN

0

這是一個奇怪的問題,一成不變的,但可變的,私營部門,而是公共...正確的方法應該是讓他們保護,因爲大家都在說。

不管怎樣,在Java中,你可以使用下三濫的手段,如果安全管理不抱怨,檢查了這一點:

import java.lang.reflect.Field; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class Priv 
{ 
    public static class A 
    { 
     private final int x; 
     public A(int x) 
     { 
      this.x = x; 
     } 
    } 

    public static class B extends A 
    { 
     public B(int x) 
     { 
      super(x); 
     } 

     public void setX(int x) 
     { 
      Class c = A.class; 
      try 
      { 
       Field f = c.getDeclaredField("x"); 
       f.setAccessible(true); 
       f.set(this, x); 
      } catch (IllegalArgumentException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (IllegalAccessException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (NoSuchFieldException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (SecurityException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 

     public int getX() 
     { 
      int v = 0; 

      try { 
       Class c = A.class; 
       Field f = c.getDeclaredField("x"); 
       f.setAccessible(true); 
       v = f.getInt(this); 
      } catch (IllegalArgumentException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (IllegalAccessException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (NoSuchFieldException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (SecurityException ex) { 
       Logger.getLogger(Priv.class.getName()).log(Level.SEVERE, null, ex); 
      } 

      return v; 
     } 
    } 

    public static void main(String[] args) 
    { 
     B b = new B(5); 

     System.out.println("b.x is " + b.getX()); 

     b.setX(42); 

     System.out.println("b.x now is " + b.getX()); 
    } 

} 
+0

您是從靜態類創建實例嗎? – JohnB

+0

不,我只是從IDE複製代碼,它是主類中的類,因此是靜態的。 – aaronps

+0

這有點讓人誤解。 – JohnB

0

沒有永恆不變的概念是你有子類的任何屬性或者構造調用super來重新初始化私有的超級類的變量。

immutable本質上是線程安全的。