- ベストアンサー
final修飾子を使用したメンバ変数宣言時の挙動について
- final修飾子を使用してオブジェクト型変数を宣言すると、変数の値は変更可能です。
- インターフェースでfinal修飾子を使用する場合、変数の値は変更できません。
- 配列の場合、final修飾子を使用して配列を宣言すると、配列自体は変更できませんが、配列内の要素は変更可能です。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
えぇと, どのようなプログラムを書きましたか? 手元では ClassB.java という名前で class ClassA { int val = 8; }; interface InterfaceA { final ClassA obj = new ClassA(); }; class ClassB implements InterfaceA { public static void main(String[] args) { InterfaceA anInterface = new ClassB(); System.out.println("val = " + anInterface.obj.val); anInterface.obj.val = 10; System.out.println("val = " + anInterface.obj.val); } }; という内容のファイルを作り, コンパイルおよび実行で動作を確認しています. ああ, javac のバージョンは javac 1.6.0_14 です.
その他の回答 (3)
- Tacosan
- ベストアンサー率23% (3656/15482)
つらつら書いたんだけど, 結局は「final をつけるとその変数そのものへの代入が禁止される」ということでいいような気がしてきた. インターフェースのメンバとして値型を使うとそのようになりますが, 参照型を使うと同じような現象が起こせます. つまり class ClassA { int val; }; interface InterfaceA { ClassA obj = new ClassA(); }; class ClassB implements Interface A { }; という場合, InterfaceA anInterface = new ClassB(); anInterface.obj.val = 10; というコードはコンパイルできます. ちなみに実験すると分かりますが final String[] hairetu = {"one","two"}; としても「変数 hairetu への代入」が禁止されるだけなので hairetu[0] = "zero"; という代入はできちゃったりします.
補足
回答ありがとうございます。 上記のソース実験してみました。 その際、anInterface.obj.val = 10;を定義すると 「staticフィールドはInterfaceA.objはstaticにアクセスする必要があります」の警告エラーが表示されるのですが、 これは、恐らくインターフェース(InterfaceA)で定義されている ClassAが実質は public static final ClassA = new ClassA();になるので そういう意味から上記のエラーが表示されるので、 一般的に final InterfaceA anInterface = new ClassB();の表示は使用せず、 obj.val = 20;のみ表示される。 といった感じなのでしょうか? また、それほど使用される回数がなさそうなのですが、 インターフェース内でクラス変数を定義する利点というのは、 クラスの入れ物を一度に複数もてる、という気がするのですが。 >final String[] hairetu = {"one","two"}; >としても「変数 hairetu への代入」が禁止されるだけなので >hairetu[0] = "zero"; よくわかりました。 以上宜しくお願い致します。
- Tacosan
- ベストアンサー率23% (3656/15482)
ちょっと質問事項がよくわからないんだけど.... 「インターフェースで考える」ってのがわからん. final の意味は場面によって異なるのですが, 「オブジェクト型の変数の定義」に final をつけると, 「その変数にはそのオブジェクトを割り当て, それ以降はこの割り当てを変更しない」という意味になります. したがって final ClassA object1 = new ClassA(); のあとに object1 = new ClassA(); とやると (変数 object1 に対するオブジェクトの割り当てを変更しようとするので)エラーとなります. ところが, final は「オブジェクトの割り当てを変更しない」と指示するだけで「オブジェクトの中身」については一切触れません. だから, 上の定義に引き続いて object1.value = 10; とやると (オブジェクトの中身は変更するけどオブジェクトの割り当てそのものは変更していないので) 問題なくコンパイルできます. インターフェース型の変数を使っても同じような現象は起こせますが, インターフェース型ではそのメンバ変数が自動的に final public static になることを考えると「もう 1段深い参照」を使うことになります.
補足
回答ありがとうございます。 詳しい説明ありがとうございます。 多少あやふやだったのでよくわかりました。 それでなのですが、 >インターフェース型の変数を使っても同じような現象は起こせますが, インーフェース型ではそのメンバ変数が自動的に final public static に>な とを考えると「もう 1段深い参照」を使うことになります. この場合だと, インターフェース InterfaceA 変数 int value = 5; IntefaceAを実装したクラスClassAがあった場合 インターフェース型は、クラスのオブジェクトをインタフェースとして扱えるようにする参照型で、クラスを定義する際、インターフェースの実装を宣言することで、インターフェース型が生成されるを踏まえると final InterfaceA inter = new ClassA(); inter.value = 20; //コンパイラエラー InterfaceAのvalue が「public static final」なので、直接代入できない。 という辺りまではわかるのですが。 「もう1段深い参照」とはどういう処理をいうのでしょうか? 宜しくお願いします。
- pcbeginner
- ベストアンサー率46% (261/560)
なんか例がよくわからないけど (ClassAのインスタンスobject1を宣言してるのに、次の行はclassA.valueだし…) 変数に「final」がつくとその変数には再代入不可ってことです。
補足
回答ありがとうございます。 質問、勘違いしていました。 classA.valueでなく、object1.value、です。 上記の方法だと、値の変更は可能でした。 宜しくお願いします。
お礼
遅くなりました。 エラーの件ですが、 @SuppressWarnings("static-access")を記載すると、 警告エラーは発生しなくなりました。 原因は正確にはわかっていませんが、調べてみます。 お礼は、一か所にまとめて書かせていただきました。 また、宜しくお願いします。
補足
回答ありがとうございます。 ソースですが、Tacosanさんが提示してくれている内容に似た感じで実行しています。 宜しくお願いします。