2012-01-10 15 views
6

スーパークラスにfinalとマークされたフィールドがあるのに、サブクラスがこのフィールドをオーバーライドする(隠す)とどうなりますか? 「ファイナル」はこれを止めませんか? 私が取り組んでいる特定の例は、さまざまな種類の建物が継承するBuildingクラスです。各タイプのコストは、とりわけ、各サブクラスに対して最終的なものでなければならないが、各タイプの建物はそれぞれ独自のコストを必要とする。Javaでの最終フィールドの継承?

編集:私は以来、私は上記話していたものをわからなかったことに気づきました。私が本当に望むのは、コストの静的変数です。しかし、スーパークラスでこれらの静的変数を宣言すると、それらはスーパークラスに対して静的であるため、たとえばSubclass1.costはSuperclass.costまたはSubclass2.costと同じ値を参照します。各クラスで宣言することなく、各サブクラスに静的な変数を作成するにはどうすればよいですか。

+0

くださいフィールドプライベート。 –

+0

費用のようなものが時々変更されますか?なぜそれが最終的になるのですか?私はフィールドを隠すことは良い考えだとは思わない。 –

答えて

11

Javaクラスのフィールドに適用されるfinalキーワードを、継承とは何の関係もありません。代わりに、コンストラクタの外側では、そのフィールドを再割り当てできないことを示します。

Javaは名前の隠蔽と上書きを別々に処理します。オーバーライドは実際にどの関数が呼び出されているかを切り替えることで、実行時のプログラムの観察可能な振る舞いを変更しますが、名前隠蔽はどのフィールドが参照されているかの静的解釈を変更することによってプログラムを変更します。 finalは、Javaのフィールドをオーバーライドすることができないため、オーバーライドに適用されるメソッドのみがメソッドのために機能します。これらの異なる状況でfinalを使用するのは少し残念ですが、残念ながらフィールドがサブクラスにその名前を隠さないようにする方法はありません。

建物のコストを変えたい場合は、オーバーライドされたgetCostメソッドをそれぞれの派生クラスで別々にオーバーライドする方法があります。また、あなたはコストを保存する基本クラスの単一protectedまたはprivateフィールドを持つことができます(これはprotectedある場合)、その後、直接このフィールドを設定し、各サブクラスを持っているか、基底クラスのコンストラクタから(このフィールドはprivateある場合)。

希望すると便利です。

+0

スーパークラスのprotectedフィールドを作成すると、サブクラスのコンストラクタで異なる値が自動的に割り当てられます。合理的に聞こえる。 – TheTedinator

+1

@ TheTedinator - これはフィールドの「最終」修飾子を忘れた場合に機能します。フィールドが 'final'の場合、サブクラスのコンストラクタで異なる値を代入することはできません。代わりに、サブクラスのコンストラクタは、割り当てられるスーパークラスのコンストラクタまで値を渡す必要があります(私の答えで示したように)。スーパークラスがそのコンストラクタに値を代入しない場合、コードはコンパイルされません。サブクラスのコンストラクタが 'final'フィールドの値をスーパークラスから設定しようとすると、コードはコンパイルされません。 –

+0

@templatetypedef "コンストラクタの外側では、そのフィールドを再割り当てできないことを示します"は実際には正しくありません。コンストラクタ内であっても、最終フィールドを再割り当てすることはできません。そのため、サブクラスのコンストラクタは、Ted Hoppが述べたように、スーパークラスの最終フィールドをオーバーライドできません。 – Sebastian

3

あなたは、この2つの方法で行うことができます。アクセサ関数を作成し、フィールド自体を非表示にしたり、他のサブクラスからスーパークラスのコンストラクタに建物費を渡します。あなたは、これらを組み合わせて、サブクラスでオーバーライドすることはできませんプロパティを行うことができます。

public class Building { 
    private final int cost; 

    protected Building(int cost, ...) { 
     this.cost = cost; 
    } 

    public final int getCost() { 
     return cost; 
    } 
} 

public class Cottage extends Building { 
    public Cottage() { 
     super(COTTAGE_COST, ...); 
    } 
} 
1

他の回答に同意しますが、私は次の実装は、この場合には優れていると思う:もちろん

public abstract class Building { 

     private final int cost; 

     public Building(int cost) { 
      this.cost = cost; 
     } 

     public final int getCost() { 
      return cost; 
     } 
    } 

    class Skyscraper extends Building { 
     public Skyscraper() { 
      super(100500); 
     } 
    } 

をフィールドには、公開作ることができるが、それは他の話だ...