• ベストアンサー

staticメソッドの継承

お世話になります。 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変数が親というのは何故なのでしょうか? 根本的な質問かもしれませんが、よろしくお願いいたします。

  • arcsin
  • お礼率46% (194/417)
  • Java
  • 回答数5
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • Gishi
  • ベストアンサー率57% (11/19)
回答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);

その他の回答 (4)

回答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"); } }

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.3

まずは static ではないメソッドで似たようなことをやるとどうなるか試してみるとよろしいかと。 > class Child extends Parent { > static{ name = "Child"; } > } それをやると、Child が初期化される前は getName() は "Parent" を返し Child が初期化された後は getName() は "Child" を返すというとんでもない混乱が待ち受けています。

arcsin
質問者

お礼

> まずは static ではないメソッドで似たようなことをやるとどうなるか試してみるとよろしいかと。 ちょっと質問の例が悪かったのですが、オブジェクトの場合、 class Parent {  private String name = "Parent";  public getName() {   return name;  } } class Child extends Parent {  public Child() {   name = "Child";  } } と書くことで、メソッドのオーバーライドをする必要がありませんが、static でも同じようなことができないかなと思って質問を致しました(説明が不十分でもうしわけありません) 何かよいデザインパターンがあればよいのですが。 (いちいちサブクラスでオーバライドするのが面倒くさい) ありがとうございます。

  • hrm_mmm
  • ベストアンサー率63% (292/459)
回答No.2

親にある関数から参照出来るのは、親が持っている変数のみです。 子側では、新たに変数宣言するのではなく、親から受け継いだ変数の中身を変更すればいいのだと思いますけど? static メンバの変更なので静的初期化子内で class Child extends Parent { static{ name = "Child"; } }

arcsin
質問者

お礼

> class Child extends Parent { > static{ name = "Child"; } > } static{} という書き方があること、勉強になりました。 ただ、なぜかおっしゃるとおりにしたのですが、どうも "Child" で初期化されませんでした。 初期化されるタイミングがあるのでしょうか。 また、静的初期化子 + メソッドをオーバーライドして試してみたのですが、#3さんがおっしゃっていた通り、親(Parent)の値も丸々書き換えてしまうようです。 ありがとうございました。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

Parent.getNameは定義しているけど、Child.getNameは定義してないんですよね。 それなら単純に、Child.getNameは存在しないので親クラスのParent.getNameが実行され、Parent.getNameのスコープにはChild.nameは存在しないのでParent.nameが参照されているだけです。 staticでなくても同様にChild.getNameはParentを返します。

arcsin
質問者

お礼

> staticでなくても同様にChild.getNameはParentを返します。 なるほど、たしかにおっしゃるとおりです。 やはりサブクラスでもオーバーライドしなければいけないみたいですね・・・。 ありがとうございます。

関連するQ&A

  • javaの継承について

    以下のコードがある場合に、想定では「child」が出力されるとおもっていたのですが、 実際は「parent」が出力されます。 3行目でChildをnewしているので16行目のメソッドが呼び出され 画面に「child」が出力されると思っていたのですが、実行結果で その考えが違う事がわかりました。 実行結果から想定すると、3行目で定義している変数sは Parentクラスを指しているため、4行目で呼び出されるメソッドは 9行目になるのかなと思っています。 しかし、Parentクラス及びChildクラスのstaticを外すと 実行結果がchildとなります。 何故staticをつけた場合とつけない場合で実行結果が 異なるのでしょうか。 ■以下コード 1:public class samplexx { 2:  public static void main(String[] args){ 3:    Parent s = new Child(); 4:    System.out.println(s.getName()); 5:  } 6:} 7:class Parent{ 8:  public static String name ="parent"; 9:  public static String getName(){ 10:    return name; 11:  } 12:} 13: 14:class Child extends Parent{ 15:  public static String name="child"; 16:  public static String getName(){ 17:    return name; 18:  } 19:}

  • 敬称について教えてください

    class parent{ protected final static int val=10; } class Child extends Parent{ private int val=100; public void method(String s){ System.out.println(++val)} } } class Test{ int val=10; public static void main(String args[]){ Parent c=new Child(); c.method("HELLO"); } } 初歩的な質問ですみません。教えて下さい。 上記プログラミングで、下から3行目のc.method・・・ を記入してもコンパイルエラーがおこらないのはなぜでしょうか? 今回newしているのはChildのオブジェクトです。 が、型はParentです。 Parentにはmethodはないし、 なぜこれが許されるのかがわかりません。 分かりやすくおしえてもらえませんか?

    • ベストアンサー
    • Java
  • コンストラクタの記述について ―引数を持ったクラスを継承する場合―

    コンストラクタの記述について ―引数を持ったクラスを継承する場合― ActionScript3.0でプログラミングをしています。 クラスの継承に挑戦したのですが、うまくいきません。 コンストラクタの記述は、何か特別なものが必要なのでしょうか? ■コンストラクタに引数なし → 成功。 ■コンストラクタに引数あり → 失敗。  エラー「No default constructor found in base class <親クラスの名前>」。 ■エラーの出るソース↓ ・Main.as(コンストラクタ内抜粋)     var parent:Parent = new Parent(100);     var child:Child = new Child(200); ・Parent.as package {   import flash.display.Sprite;      public class Parent extends Sprite {     protected var str:String = "親クラスのプロパティ";     public function Parent(inNum:Number):void {       trace("親クラス, ", str, inNum);     }   } } ・Child.as package {   import Parent;   public class Child extends Parent {     public function Child(inNum:Number):void { //■エラー。       trace("子クラス, ", str, inNum);     }   } } ご存知の方、よろしくお願いします。 よろしくお願いします!

    • ベストアンサー
    • Flash
  • 継承・実装の関係で悩んでいます。

    継承・実装の関係について悩んでいます。 ここでは、アクセス制御を考えずに、インスタンスかstaticかabstract(ここではabstract final staticやabstract classのこと)の違いで、どう継承するのか考えています。 // 継承 はメソッドのオーバーライドのことを考えます。(オーバーロードは考えない) クラスAからクラスBでオーバーライドしたメソッドは、 クラスCでさらにオーバーライドできるのでしょうか? クラスCが クラスBのクラスAからオーバーライドしたメソッド をクラスBのメソッドとして見たときに、オーバーライドすることは可能なのでしょうか? クラスA │ インスタンスフィールドA │ staticフィールドA │ │ クラスA() { } │ │ インスタンスメソッドA () { } │ staticメソッドB() { } ↓ クラスB extends クラスA │ インスタンスフィールドA // 継承 │ インスタンスフィールドB │ staticフィールドB │ │ サブクラス1() { } // コンストラクタは継承しない、super()で呼び出す │ │ インスタンスメソッドA () { } // 継承 │ │ インスタンスメソッドB () { } │ staticメソッドB () { } ↓ クラスC extends クラスB implements インタフェースD, ... ↑ インスタンスフィールドA // クラスBのフィールドを継承 │ インスタンスフィールドB // クラスBのフィールドを継承 │ インスタンスフィールドC │ staticフィールドC │ │ サブクラス2() { } │ │ インスタンスメソッドA () { } // クラスBのメソッドを継承 │ インスタンスメソッドB () { } // クラスBのメソッドを継承 │ インスタンスメソッドD () { } // インタフェースDのメソッドを実装 │ インスタンスメソッドE () { } // インタフェースDのメソッドを実装 │ │ │ インスタンスメソッドC () { } │ staticメソッドC() { } │ interface インタフェースD extends インタフェースE ↑ │ staticフィールドD // public static final │ │ インスタンスメソッドD() { } // public abstract │ インスタンスメソッドE() { } // 継承 │ interface インタフェースE staticフィールドE // public static final インスタンスメソッドE() { } // public abstract

    • ベストアンサー
    • Java
  • PHPでのstatic(静的)メソッド・メンバの継承について教えてください。

    次のような例にて、私の考えているように動作しません。 class ClassA {  protected static function method1()  {  echo "111";  }  public static function method2()  {  self::method1();  } } class ClassB extends ClassA {  protected static function method1()  {  echo "222";  } } ClassB::method2(); // ---> 111 と表示される。 ------ 私としては、222と表示されると予測していたのですが、 思ったように動作しません。 継承された子クラスClassBにて、method2() が実行され、 その中での self::method1(); のselfが、 ClassBではなく、親クラスのClassAを指し示していると思われます。 私としては、継承された子クラスでのselfは、相対的に、子クラスをあらわしてほしいのですが。 そういうものだ、と言われればそれまでなのですが、 これだと、self::method1(); でも、ClassA::method1(); でも同じことになってしまい、 selfの存在意義がないことになってしまうのでは?と思うのです。 私の理解のどこが間違っているのか教えていただけると幸いです。 どうぞよろしくお願いします。

    • 締切済み
    • PHP
  • static変数を持ったクラスを継承した複数のクラスで、独立してその変

    static変数を持ったクラスを継承した複数のクラスで、独立してその変数を使いたい。 例えば、 class AbstractStatic{ public static String str; } class Ex1 extends AbstractStatic{} class Ex2 extends AbstractStatic{} というクラスがあったとして、 Ex1 e1 = new Ex1(); ex1.str = "hoge"; といれると、 ex2.str で、hogeが入ってしまいます。同じようなstatic変数を持つクラスを複数作りたいのですが、継承させると、独立して変数を持たせられません。 同じようなクラスに直接static変数を、記述するしかないのでしょうか?

    • ベストアンサー
    • Java
  • mainメソッドと同じオブジェクト内のメソッドにはstaticを必ずつ

    mainメソッドと同じオブジェクト内のメソッドにはstaticを必ずつけなければならないのでしょうか? そのような記述を見掛けたのですが、もしこれが正しいという場合、 それは、なぜなのでしょう? java初心者ですが、どうぞ宜しくお願いいたします。 class MainClass{  //先頭のstaticに注目  static void sub(){   ~~  }  //mainメソッド  public static void main(String[] args){   sub();  } }

    • ベストアンサー
    • Java
  • getInsets() メソッドの使い方について

    JAVA言語を勉強中の者です getInsets() メソッドでフレームの外周に空白部分を 作るのですが、その場合は以下のように   public Insets getInsets(){     return new Insets(40,10,10,10);   } とオーバーライドするとあります。 オーバーライドのみで外周に空白ができるのを確認できたのですが このオーバーライドされたメソッドをフレームのコンストラクター内等でgetInsets(); とメソッドを書かなければ, このメソッドはフレームに反映されなのではないかと考えているのですが、 実際は書かなくても外周の空白はきっちりととれます。 どうしてオーバーライドのみでこのメソッドは実行結果に反映されるのでしょうか。 よろしくお願いします   MyFrame(String ss){     .............     getInsets(); //この記述不要で動作します     .............   } 簡単なソースを記述しました import java.awt.*; public class Sample{   public static void main(String args[]){     MyFrame frame = new MyFrame("Sample.java");     frame.setSize(200,200);     frame.setVisible(true);   } } class MyFrame extends Frame{   Button b1, b2, b3, b4;   MyFrame(String ss){     super(ss);     setLocation(100,100);     setLayout(new GridLayout(2,2));     //getInsets(); この記述がないと外周空白はできないと考えています     add(b1=new Button("1"));     add(b2=new Button("2"));     add(b3=new Button("3"));     add(b4=new Button("4"));   }   public Insets getInsets(){     return new Insets(40,10,10,10);   } }

    • ベストアンサー
    • Java
  • 継承について

    下の質問の回答、間違ってませんか? -------------------------------------------- 親クラスのフィールドをメソッドを全て継承することになります。よって、サブクラス2は、サブクラス1とスーパークラスのメンバーを全て持つことになります。サブクラス2をインスタンス化すると、サブクラス1とスーパークラスが全てインスタンス化(コンピューターのメモリ上等に配置)されます。 ただ、可視性というものがあり、サブクラスから親クラスのメンバーを直接取り扱えない場合があります。privateや可視性修飾子無しの場合、サブクラスから直接取り扱えません。ただ、継承はされているので、インスタンスとしては存在します。例えば、 class スーパークラス{ private int abc; public int getAbc(){ return this.abc; } というクラスがあり、これを継承したサブクラスがあったとします。 サブクラスからは、privateなメンバー変数abcは直接取り扱うことができません。ただ、publicなgetAbcメソッドはサブクラスから取り扱えます。これで何が分かるかといいますと、privateなメンバーでもサブクラスに継承されるのです。単に可視性の問題で直接取り扱えないだけなのです。 また、オーバーライドされたメソッドがあったとしても、super.メソッド()で親のメソッドも呼べますので、これも継承されているのです。

  • 継承について

    継承についてです。 class A { int x; } class B extends A{ public int test(){ return 1; } public static void main(String[]args){ A a = new B; a.test(); } } としたとき a.test(); という記述はできないものなのでしょうか?a.textでコンパル時にエラーが出ます。aはBのインスタンスを指しているから、test()もつかえるんじゃないかなとおもったのですが・・・ public int test(){return 0;}というのをクラスAに記述すればエラーは起こりませんが、これはわかります。 ウェブを探したのですが、検索の仕方が悪かったのかこれに関する記事をさがせなかったので質問いたしました。

    • ベストアンサー
    • Java

専門家に質問してみよう