お世話になります。
static メソッドの継承についてなのですが、
class Parent {
public static String name = "Parent";
public static getName() {
return name;
}
}
class Child extends Parent {
public static String name = "Child";
}
だと、
Parent.getName();
Child.getName();
はともに Parent を返します。
ChildにてgetName()をオーバーライドすれば望む結果が得られるのですが、何かスマートでは無いような気がしてしまいます。
継承したstaticメソッドは親の元で実行され、そしてアクセスするstatic変数が親というのは何故なのでしょうか?
根本的な質問かもしれませんが、よろしくお願いいたします。
No.4ベストアンサー
- 回答日時:
static なフィールドやメソッドというのは
(正確な説明ではないかもしれませんが)
他の言語で言うところの
「グローバル変数」「グローバル関数」みたいなものです。
つまり、
class Parent {
public static String name = "Parent";
public static String getName() {
return name;
}
}
class Child extends Parent {
public static String name = "Child";
}
上のコードは、
下のようなものだと考えてみてください。
String Parent_name = "Parent";
String Child_name = "Child";
String Parent_getName() {
return Parent_name;
}
Child.getName() が
"Child" でなく "Parent" を返す理由が分かると思います。
単純にクラス名を取得したいのであれば、
Parent.class.getName()
Child.class.getName()
を使うという方法があります。
もうすこし一般的な解決法としては、
ハッシュテーブルを使ってみるのもよいかもしれません。
Hashtable table = new Hashtable();
table.put(Parent.class, "Parent");
table.put(Child.class, "Child");
String p = (String)table.get(Parent.class);
String c = (String)table.get(Child.class);
Java 5.0 では下のような書き方になります。
Map<Class,String> table = new HashMap<Class,String>();
table.put(Parent.class, "Parent");
table.put(Child.class, "Child");
String p = table.get(Parent.class);
String c = table.get(Child.class);
No.5
- 回答日時:
staticなフィールドはクラスに張り付いています。
つまり、オブジェクトを2つ作った場合にstaticでないフィールドはそれぞれのオブジェクトについてフィールドが生成されますが、staticなものはクラスに張り付いているので、そのフィールドはクラス間で共有されています。そして、サブクラスでもその関係は同等です。あなたが書いている通りサブクラスでフィールドの値を置き換えた場合、staticでないものに関してはそれぞれのオブジェクトに関してフィールドが生成されているのでスーパークラスとサブクラスで値を変えることができますが、staticなものに関してはフィールドを共有しているので、サブクラスで値を変えられたときはスーパークラスまでその変更が影響してきます。
スーパークラスとサブクラスで共有しているフィールドを返そうとしているのに、違う値を返すことはできるでしょうか?当然できませんね。だから、オーバーライドするのが正解でしょう。
>いちいちサブクラスでオーバライドするのが面倒くさい
とありますが、サブクラスのコンストラクタでフィールドを変更するコードをかく手間とどこが違うのかが自分にはよくわかりません。
見た目が美しいか美しくないかと言う感覚ならよくわかりますが。
同じオブジェクト、違うオブジェクトに関しては下記のコードを試してみてください。よくわかると思います。
public class Parent {
protected static StringBuffer p_sb1=new StringBuffer("parent_sb1");
protected StringBuffer p_sb2=new StringBuffer("parent_sb2");
static StringBuffer get_sb1()
{
return p_sb1;
}
StringBuffer get_sb2()
{
return p_sb2;
}
public static void main(String args[])
{
Parent p1=new Parent();
Parent p2=new Parent();
System.out.println("p1.p_sb1とp2.p_sb1は"+checkSameObj(p1.p_sb1,p2.p_sb1));//staticなフィールドにはstaticにアクセスするべき
System.out.println("p1.p_sb2とp2.p_sb2は"+checkSameObj(p1.p_sb2,p2.p_sb2));
System.out.println("p1.get_sb1()とp2.get_sb1()は"+checkSameObj(p1.get_sb1(),p2.get_sb1()));//staticなフィールドにはstaticにアクセスするべき
System.out.println("p1.get_sb2()とp2.get_sb2()は"+checkSameObj(p1.get_sb2(),p2.get_sb2()));
System.out.println("----------");
System.out.println("Parent.p_sb1とChild.p_sb1は"+checkSameObj(Parent.p_sb1,Child.p_sb1));
System.out.println("Parent.get_sb1()とChild.get_sb1()は"+checkSameObj(Parent.get_sb1(),Child.get_sb1()));
System.out.println("----------");
Child c1=new Child();
System.out.println("p1.p_sb1とc1.p_sb1は"+checkSameObj(p1.p_sb1,c1.p_sb1));//staticなフィールドにはstaticにアクセスするべき
System.out.println("p1.p_sb2とc1.p_sb2は"+checkSameObj(p1.p_sb2,c1.p_sb2));
System.out.println("p1.get_sb1()とc1.get_sb1()は"+checkSameObj(p1.get_sb1(),c1.get_sb1()));//staticなフィールドにはstaticにアクセスするべき
System.out.println("p1.get_sb2()とc1.get_sb2()は"+checkSameObj(p1.get_sb2(),c1.get_sb2()));
System.out.println("----------");
System.out.println("p1.p_sb1とp2.p_sb1は"+checkSameObj(p1.p_sb1,p2.p_sb1));//staticなフィールドにはstaticにアクセスするべき
System.out.println("p1.p_sb2とp2.p_sb2は"+checkSameObj(p1.p_sb2,p2.p_sb2));
System.out.println("p1.get_sb1()とp2.get_sb1()は"+checkSameObj(p1.get_sb1(),p2.get_sb1()));//staticなフィールドにはstaticにアクセスするべき
System.out.println("p1.get_sb2()とp2.get_sb2()は"+checkSameObj(p1.get_sb2(),p2.get_sb2()));
System.out.println("----------");
System.out.println("Parent.p_sb1とChild.p_sb1は"+checkSameObj(Parent.p_sb1,Child.p_sb1));
System.out.println("Parent.get_sb1()とChild.get_sb1()は"+checkSameObj(Parent.get_sb1(),Child.get_sb1()));
}
static String checkSameObj(Object o1,Object o2)
{
if(o1==o2)
{
return "同じオブジェクト/o1:"+o1+",o2:"+o2;
}
else
{
return "違うオブジェクト/o1:"+o1+",o2:"+o2;
}
}
}
class Child extends Parent
{
static
{
p_sb1=new StringBuffer("child_sb1");
}
Child()
{
p_sb2=new StringBuffer("child_sb2");
}
}
No.3
- 回答日時:
まずは static ではないメソッドで似たようなことをやるとどうなるか試してみるとよろしいかと。
> class Child extends Parent {
> static{ name = "Child"; }
> }
それをやると、Child が初期化される前は getName() は "Parent" を返し Child が初期化された後は getName() は "Child" を返すというとんでもない混乱が待ち受けています。
> まずは static ではないメソッドで似たようなことをやるとどうなるか試してみるとよろしいかと。
ちょっと質問の例が悪かったのですが、オブジェクトの場合、
class Parent {
private String name = "Parent";
public getName() {
return name;
}
}
class Child extends Parent {
public Child() {
name = "Child";
}
}
と書くことで、メソッドのオーバーライドをする必要がありませんが、static でも同じようなことができないかなと思って質問を致しました(説明が不十分でもうしわけありません)
何かよいデザインパターンがあればよいのですが。
(いちいちサブクラスでオーバライドするのが面倒くさい)
ありがとうございます。
No.2
- 回答日時:
親にある関数から参照出来るのは、親が持っている変数のみです。
子側では、新たに変数宣言するのではなく、親から受け継いだ変数の中身を変更すればいいのだと思いますけど?
static メンバの変更なので静的初期化子内で
class Child extends Parent {
static{ name = "Child"; }
}
> class Child extends Parent {
> static{ name = "Child"; }
> }
static{}
という書き方があること、勉強になりました。
ただ、なぜかおっしゃるとおりにしたのですが、どうも "Child" で初期化されませんでした。
初期化されるタイミングがあるのでしょうか。
また、静的初期化子 + メソッドをオーバーライドして試してみたのですが、#3さんがおっしゃっていた通り、親(Parent)の値も丸々書き換えてしまうようです。
ありがとうございました。
No.1
- 回答日時:
Parent.getNameは定義しているけど、Child.getNameは定義してないんですよね。
それなら単純に、Child.getNameは存在しないので親クラスのParent.getNameが実行され、Parent.getNameのスコープにはChild.nameは存在しないのでParent.nameが参照されているだけです。
staticでなくても同様にChild.getNameはParentを返します。
> staticでなくても同様にChild.getNameはParentを返します。
なるほど、たしかにおっしゃるとおりです。
やはりサブクラスでもオーバーライドしなければいけないみたいですね・・・。
ありがとうございます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java final 1 2022/06/10 22:49
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- Java 直し方について教えて頂きたいです。 4 2022/08/13 02:11
- Java eclipse実行ができない 2 2022/07/27 04:47
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- C言語・C++・C# Windows Formアプリからコンソールを呼び出して文字を出力させたい 8 2023/05/09 10:53
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
カタカナの小文字を大文字に変...
-
C#の質問
-
改行コードの置換が…
-
JAVA Servlet での全角文字判定
-
System.err. printlnとSystem.o...
-
C言語のポインターに関する警告
-
0dの意味を教えてください
-
JSPでHashMap・配列の変数の値...
-
VB.net 引数で配列変数を渡す際...
-
eclipseに記述したjavaファイル...
-
プログラミングの問題です。大...
-
JSPやサーブレットでSystem.out...
-
VBAで配列の計算
-
ORA-01858: 数値を指定する箇所...
-
オブジェクトの中のプロパティ...
-
Path型をString型へ変換する(Java)
-
ループ処理の際、最後だけ","を...
-
パソコンキーボードで時分秒を...
-
EXCEL VBA で、0から?1から?
-
java キーボード入力された値の...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
カタカナの小文字を大文字に変...
-
staticメソッドの継承
-
C# 特定文字の数を調べる方法を...
-
改行コードの置換が…
-
小文字、大文字変換
-
C#の質問
-
JAVA Servlet での全角文字判定
-
教えてください
-
JAVAで全角カナチェックの方法
-
正規表現で少し複雑な置換がしたい
-
C言語のポインターに関する警告
-
System.err. printlnとSystem.o...
-
JSPやサーブレットでSystem.out...
-
[JAVA]try 内の変数を外で!?
-
javaで質問です。 文字列2023/2...
-
flush()とclose()について
-
ループ処理の際、最後だけ","を...
-
Javaで改行などが出来ないのです。
-
ダブルクォーテーションのrepla...
-
応用情報技術者試験の令和元年...
おすすめ情報