Java
1public class Base { 2 public final int zzz; 3 public Base() { 4 } 5 public Base(int a, int b, int c) { 6 //長い処理 7 } 8} 9 10public class Derived extends Base { 11 12}
このような関係になっているときに、Baseクラスのpublic final intフィールドzzzをDerivedクラスで初期化することはできますでしょうか。
Base(int,int,int)コンストラクタは、Baseクラスをそのまま使うときに呼び出すものですのでDerivedから呼ぶことはできません。
DerivedクラスではBaseクラスの初期化処理だけを変更して、それ以外のメソッドはそのまま流用したいという使い方をしたいと思っています。
BaseクラスのBase()コンストラクタでzzzに何の値も入れないと怒られますし、Derivedクラスではzzzに値を入れることができないという状態です。
クラス構造を変更するしか方法がないのでしょうか?
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
行儀の悪いコードであることは百も承知ですが、当初やりたかったことは
Javaのリフレクションを用いることにより実現できました。
import java.lang.reflect.Field; class Base { public final int zzz; public Base() { // dummy zzz = 0; } public Base(int a, int b, int c) { // 長い処理 zzz = 123; } } class Derived extends Base { public Derived() { try { Field f = getClass().getSuperclass().getDeclaredField("zzz"); f.setAccessible(true); f.set(this, 345); // 新しい値を設定 } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) { e.printStackTrace(); } } public static void main(String[] args) { Derived der = new Derived(); System.out.println(der.zzz); } }
投稿2016/02/07 12:42
総合スコア71
0
Base(int,int,int)コンストラクタは、Baseクラスをそのまま使うときに呼び出すものですのでDerivedから呼ぶことはできません。
であればそもそも継承して使うという事自体が間違っているのでは?
機能拡張するからこその継承であって、それを禁止するのなら継承という手段を使うのは適切ではないという事になります。
Baseクラスでzzzを初期化しないのならそもそもzzzというfinalフィールドが存在するべきではありませんし、値を変更できるようにしたいなら最低でもzzzに代入する数値を受け取るコンストラクタが必要です。
もう一つのコンストラクタBase(int, int, int)
もそのコンストラクタを経由するようにもできますし、zzzに代入する値を渡すためのコンストラクタは設計上絶対必要だと思いますよ。
java
1public Base { 2 public final int zzz; 3 public Base() { 4 zzz = 0; //何か代入しなければいけない。もしくはこのコンストラクタ自体を削除する 5 } 6 7 //zzzを任意の値で初期化するためのコンストラクタ 8 public Base(int z){ 9 zzz = z; 10 } 11 12 public Base(int a, int b, int c) { 13 this(a); //zzz初期化のコンストラクタ起動 14 //代入する値が何らかの長い計算によって出す必要があるなら、 15 //private staticなメソッドでも作ってそちらに計算を一任してこのaの部分に渡す 16 //あるいはコンストラクタの形ではなく、ファクトリメソッドでこのパターンを用意 17 } 18} 19 20public Derived extends Base { 21 public Derived(int z){ 22 super(z); //zzzを初期化するコンストラクタを呼び出す 23 //その他処理 24 } 25}
追記
ファクトリメソッドでの書き方
java
1class Car { 2 3 // Carの性能を表す変数(読み取り専用) 4 public final int spec; 5 6 Car() { 7 spec = 0; 8 } 9 10 // ファクトリメソッドで生成することを想定するためprivateにしたかったが、 11 // 継承して使えなくなるためprotectedにする 12 protected Car(int s) { 13 spec = s; 14 } 15 16 //ファクトリメソッド 17 public static Car createCar(int a, int b, int c) { 18 //長い計算 19 return new Car(計算結果); 20 } 21 22 // Carの多数のメソッド 23} 24 25class SuperCar extends Car { 26 27 SuperCar(int s) { 28 super(s); 29 } 30 31 //SuperCarのファクトリメソッド 32 public static SuperCar createSuperCar(仮パラメータ) { 33 //計算する 34 return new SuperCar(計算結果); 35 } 36 37 // SuperCarの多数のメソッドは、Carと共通 38 // だからSuperCarはCarを継承させた。 39}
投稿2016/02/07 09:31
編集2016/02/07 13:01総合スコア20649
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/02/07 12:49
2016/02/07 13:48
2016/02/07 16:13
0
ベストアンサー
できません。
( Derived のコンストラクタで super( a, b, c) を呼ぶならできますが、呼べないというお話ですので)
そういうことができないということを保証してくれるのが final のありがたい機能です。
そもそも何のために zzz を final にしているのですか?
final というのはコンストラクタで一度きりしか値が設定されないようにしたいから指定するもので、
そういう記述をしたプログラマの意図に沿うためにわざわざ、エラーが出るようになっているのですから、
それを無理に変えることは、当初のあなたの(zzz を final にした)目的と矛盾しませんか?
投稿2016/02/06 12:23
総合スコア1193
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/02/06 12:44
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。