- PR -

クラスオブジェクト変数の宣言について

1
投稿者投稿内容
Nana
会議室デビュー日: 2008/07/07
投稿数: 10
投稿日時: 2008-09-04 20:53
JAVAを勉強中のものです。
自己解決ができない状況におちいってしまったため
質問させてください。

質問の内容はクラスオブジェクトを作成する際、
Superクラスで変数を宣言してnewはSubクラスを指定する
ことがあると思うのですが、これはSubクラスで変数を宣言
するのとではどのような違いがあるのでしょうか?

メソッドはnewで指定したSubクラスのコンストラクタが呼ばれるのは
以下のサンプルコードを実行してわかったのですが、メンバ変数
はSuperクラスの値でした。

これは参照先がnewで作成したインスタンスを指しているから
メソッドはSubクラスが呼ばれるのはわかったのですが
メンバ変数は参照ではないということになるのでしょうか?
すみません。意味不明な文面になってしまいましたが
宜しくお願いします。

------サンプル-------

public class Hoge{
public static void main(String[] args) {
XXX x1 = new XXX();
YYY x2 = new XXX();
YYY y1 = new YYY();

System.out.println("x1: S=" + x1.s + " met=" + x1.print());
System.out.println("x2: S=" + x2.s + " met=" + x2.print());
System.out.println("y1: S=" + y1.s + " met=" + y1.print());
}
}

class XXX extends YYY{
String s = "XXX";
String print(){
return "XXXメソ";
}
}

class YYY{
String s = "YYY";
String print(){
return "YYYメソ";
}
}

****出力結果****
x1: S=XXX met=XXXメソ
x2: S=YYY met=XXXメソ ★ここがわかりません。
y1: S=YYY met=YYYメソ
****************
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2008-09-05 09:59
クラス変数はオーバーライドされません。
隠蔽されるだけです。
Nana
会議室デビュー日: 2008/07/07
投稿数: 10
投稿日時: 2008-09-05 20:46
Edossonさん返答ありがとうございます。

隠蔽についてもう少し詳しく教えて頂いてもよろしいでしょうか?

「XXX x1」で宣言したものも「YYY x2」で宣言したものも
eclipseの変数を見ると、s="XXX"とs="YYY"どちらも
初期化され保持していました。

これがx2の場合はなぜ「"YYY"」が選択され出力するのかが分かりません。
おそらくこれを理解しないと共通APIのインスタンスを作成するときの

スーパクラス s = new サブクラス();
サブクラス s = new サブクラス();

をきちんと使い分けられないような気がしてしまったためしつこい
返答となってしまいましたがよろしくお願いします。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2008-09-05 22:46
XXXクラスのインスタンスは、YYYクラスのsとXXXクラスのsの2つを別々に持つことになります。

メソッドの呼び出しは実際のインスタンスの型で決まります。なので、変数の型が何であろうと new XXX()した場合は print() は XXX で定義したものが呼ばれますよね。

メンバ変数のアクセスはインスタンスが入っている変数の型で決まります。なので、実際のインスタンスの型がXXXだろうとYYYだろうと、YYYの変数からアクセスすればYYYクラスのsが見えます。

同名メンバ変数のこの挙動はわかりにくいので、通常は同名のメンバ変数は使わないように注意します。同名のメンバ変数が使えてもまったく嬉しくないので。
Nana
会議室デビュー日: 2008/07/07
投稿数: 10
投稿日時: 2008-09-06 00:44
スフレさん。ご返答ありがとうございました。

とても丁寧な回答のお陰でこんな私でも理解することができました。
最後にAPIで宣言する際の以下2つについては、基本メンバ変数に
を使用しない環境下であればまったく同じという考えで問題ないので
しょうか?

スーパクラス s = new サブクラス();
サブクラス s = new サブクラス();

実例:
Map map1 = new HashMap<Integer, String>();
HashMap map2 = new HashMap<Integer,String>();
Nana
会議室デビュー日: 2008/07/07
投稿数: 10
投稿日時: 2008-09-06 00:53
すみません。実例といいながらインターフェースと実装クラスで
書いてしまったので、訂正します。

実例:
AbstractList<String> list = new ArrayList<String>();
ArrayList<String> list = new ArrayList<String>();

ただよく見かけるのは
List<String> list = new ArrayList<String>();
ArrayList<String> list = new ArrayList<String>();
なので
インターフェース s = new 実装クラス();
実装クラス s = new 実装クラス();
で質問すべきだったのですかね。。。。

すみません。なんだか混乱してきてしまいました。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2008-09-07 11:25
変数の型は「必要なメソッドを持つ最も抽象的な型」になるのが理想です。ArrayListよりAbstractListのほうが良いかもしれませんが、この場合はインターフェイスであるListが適切かと思います。抽象クラスよりインターフェイスのほうが抽象度は高いと言えます。

勉強中ということであれば、まずは実際の型と変数の型は一致させてしまっていいと思いますよ。それで困ることはまずありませんので。
Nana
会議室デビュー日: 2008/07/07
投稿数: 10
投稿日時: 2008-09-07 19:41
スフレさん、ご返答ありがとうございます。

「一致させてしまっていいと思いますよ。」
了解しました。
もっとAPIそれぞれの特徴を理解し、スタックやヒープに
ついてもう少し理解したら再度考えてみたいと思います。

色々ご指導頂きありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)