インタフェースの抽象メソッドをオーバーライドする方法

このQ&Aのポイント
  • Javaのインタフェースに関する質問です。インタフェースを実装してクラスを宣言し、そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する方法について説明します。
  • インタフェースの抽象メソッドへの定義の与え方やその実行のされ方について、メソッドのオーバーライドと同様と思われるが、実際には文法エラーとならない場合があります。
  • 具体的なコード例を示し、その実行結果も紹介します。また、Javaのバージョンによって挙動が異なることも触れます。
回答を見る
  • ベストアンサー

「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」

「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」は正しい? はじめまして。Javaのインタフェースに関する質問です。 私はこれまで、インタフェースを使うときは、インタフェースを実装してクラスを宣言し、そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する、と理解していました。 しかし、下の例をみてください。抽象メソッドの定義を、インタフェースの実装の以前で与えています。問題無くコンパイルでき、実行できます。実行結果も以下の通りです。 インタフェースの抽象メソッドへの定義の与え方やその実行のされ方は、メソッドのオーバーライドと同様と思っていましたので、下記のコードでは「クラスBが抽象クラスではありません」や、「インタフェースの抽象メソッドがオーバーライドされていません」などの文法エラーがでると思っていました。 そこで、質問です。 インタフェースが持つ抽象メソッドの定義を与える場所について、または、これに関する説明のあるページなど、何かご存知でしたら教えてください。 ★コード★ interface X{   void show(); } class A{   public void show(){     System.out.println("A");   } } class B extends A implements X{ } public class Main{   public static void main(String[] args){     X x=new B();     x.show();   } } ★実行結果★ >java Main A ★Java環境★ java 1.6.0_21 javac 1.6.0_16

  • Java
  • 回答数6
  • ありがとう数8

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

  • ベストアンサー
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.6

> インタフェース型の変数を用いた場合の、メソッドの宣言の見つけ方は、メソッドのオーバーライドの場合とは別物なのでしょうか? JavaプログラムをJavaバイトコードにコンパイルすると普通のインスタンスメソッドの呼び出しはinvokevirtualに、インタフェース経由のメソッド呼び出しはinvokeinterfaceになります。しかし、これらのバイトコードが実行時にメソッドを探し出す手順は同じです。 interface I { void m(); } class B extends A { ~ } class C extends B implements I { ~ } class D extends C { ~ } というクラス階層があったとして、 I obj = new D(); obj.m(); というメソッド呼び出しがあった場合、 ・Dにm()の定義があればそれを呼ぶ ・DになければC→B→Aとクラス階層を順にさかのぼってm()の定義を探す となります。 インタフェースだからと言って特別な事はしていないし、Iで宣言されているメソッドの実体がAにあっても問題ないことが分かると思います。

maki_maki_
質問者

お礼

salsberryさん 的確なご回答有難うございました。 頂いたキーワードinvokevirtualとinvokevirtualからVMの仕様書に辿りつきました。 The JavaTM Virtual Machine Specification http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc6.html 仕様書内では、インタフェース型の変数を用いた場合のメソッドの検索手順とクラス型の変数を用いた場合のメソッドの検索手順が明確に記述されていました。細かな違いはあるものの、ほぼ同じ手順で検索されていること、またその手順そのものが分かりました。 salsberryさんのご指摘通りで、メソッドの探索は、末端のサブクラスからスーパークラスの方へ向って行われるんですね。 結果的に、インタフェースの抽象メソッドの実体は、インタフェースが実装されているクラスの前後どこかにあれば良いとなりますね。 有難うございました。

その他の回答 (5)

回答No.5

こんにちは。 補足、拝見しましたが・・・、 ちょっと質問の意味がわかりかねます。 どのようなところが疑問なのでしょう? 例えば・・・、で結構ですので、補足して頂けますか?

maki_maki_
質問者

お礼

taka451213さん 質問が分かり難くて申し訳ありませんでした。明確にすると、次のコードを実行したとき、(1)の場合と(2)の場合では、メソッドの探索の仕方は異なりますか?というものでした。 その後、皆さんからのご回答を参考にあちこち情報を探し回りました。その結果、(1)と(2)ではメソッドの探索手順をほぼ同じことが分かり、末端のサブクラスからスーパークラスへと再帰的に探すということでした。 結果的に、皆さんからご指摘頂いたように「インタフェースがもつ抽象メソッドの定義は、インタフェースを実装しているクラス、またはそのスーパークラスかサブクラスのどこかにあれば良い」となりますね。 ご回答有難うございました。 ★コード★ interface X{   void show1(); } class A{   public void show1(){     System.out.println("A1");   }   public void show2(){     System.out.println("A2");   } } class B extends A implements X{   public void show2(){     System.out.println("B2");   } } public class Main{   public static void main(String[] args){     B b=new B();     A a=b;     X x=b;          x.show1(); // (1)インタフェース型変数     a.show2(); // (2)クラス型変数   } } ★実行結果★ >java Main A1 B2

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

確認したいことがあります. 「もし、メソッドのオーバーライドの要領で、スーパークラス(インタフェース)に宣言されているメソッドを実行しようとしたら、サブクラス(インタフェースが実装されたクラス、またはこのクラスのサブクラス)で宣言されている同じメソッドが実行されるとは、考えることができなくなりそうです。」 というのは, どういうことでしょうか? 基本的には同じようにメソッドを検索するような気がするのですが....

maki_maki_
質問者

お礼

Tacosanさん Tacosanのおっしゃる通り、インタフェース型の変数を用いた場合とクラス型の変数を用いた場合において、メソッドを検索する手順はほぼ同じであることが分かりました。 「もし、メソッドのオーバーライドの要領~」は、メソッドの探索手順についての私の誤解でした。例えば、以下のコードを見て下さい。(1)と(2)の個所で両者ともにクラスAのshow()メソッドを呼び出そうとしています。結果的にはオーバーライドの機能により実行されるメソッドはサブクラスCに宣言されているものです。クラス型の変数を用いてメソッドにアクセスする場合は、常に最も下で宣言されているメソッドが実行されます。この点から生じた誤解でした。 ★コード★ class A{   public void show(){     System.out.println("A");   } } class B extends A{ } class C extends B{   public void show(){     System.out.println("B");   } } public class Main{   public static void main(String[] args){     C c=new C();     B b=c;     A a=c;     a.show(); //(1)     b.show(); //(2) } } ★実行結果★ >java Main B B メソッドを探索する手順は、正しくは、「スーパークラス(インタフェース)に宣言されているメソッドを実行しようとしたら、末端のサブクラス(インタフェースが実装されたクラスの末端のサブクラス)からスーパークラスへ再帰的に同じメソッドを探索し、見つかったメソッドを実行する」となりそうです。 ご回答有難うございました。

回答No.3

> 私はこれまで、インタフェースを使うときは、インタフェースを実装してクラスを宣言し、 > そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する、 > と理解していました。 > しかし、下の例をみてください。抽象メソッドの定義を、インタフェースの実装の以前で > 与えています。問題無くコンパイルでき、実行できます。実行結果も以下の通りです。 抽象メソッドの定義(インタフェースの実装)を前に書くか後に書くかは、関係ありません。 インタフェースXをimplementsしたクラスBにshowメソッドが実装されていればよいわけです。 クラスBの定義部分には、showメソッドは書いてありあせんが、クラスAを継承しており、クラスAでshowメソッドが実装されている為、クラスBで、showが実装されていると言えます。 例えば、次の例で、クラスBの定義部分には、showメソッドがありませんが、クラスBをnewした変数bで、showメソッドが使えます。 これは、クラスAを継承している為、クラスBで、showが実装されている事になるからです。 class A{   public void show(){     System.out.println("A");   } } class B extends A { } public class Main{   public static void main(String[] args){     B b=new B();     b.show();   } } http://msugai.fc2web.com/java/interface.html 上記ページにインタフェースの説明がありますが、「インタフェースの実装」の部分で、次のような記述があります。 > インタフェースを実装したら、そこで定義されている抽象メソッドを全て実装しておかないと > コンパイルエラーになります。 ここで、抽象メソッドを全て実装するのは、そのクラスの定義部分でも継承元でもかまいません。 ただし、publicで実装しなければなりません。 継承元にpublicで実装してあれば、継承先でもそのメソッドを実装している事になります。

maki_maki_
質問者

お礼

yossy_sas2000さん ご回答有難うございました。 >抽象メソッドの定義(インタフェースの実装)を前に書くか後に書くかは、関係ありません。 この点に関するホームページを紹介して頂き有難うございます。確認することができました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

#1 と同じなんだけど, 結局 ・インターフェイスX を実装する具象クラスは void show() を持っていなければならない ・クラスB は (クラスA から継承した) void show() を持っている ので大丈夫, と.

maki_maki_
質問者

補足

早々のご回答有難うございます。 Tacosanさんのお考えも、taka451213さんと同じようですね。 taka451213さんへ再度質問させて頂きましたが、インタフェース型の変数で、そのインタフェースがもつ抽象メソッドへアクセスした場合に、どのように実際のメソッドの定義を見つけるのかについて何かご存知でしたらお知らせお願いします。 質問内容は、taka451213さんへの補足をご参照頂ければと思います。

回答No.1

こんばんは。 特に不思議ではないですが・・・? クラスBはクラスAをextendsしているので、interface Xをimplementsするための要件は満たしています。 ただ、このimplementsをBに書くのに違和感を感じますが・・・。 まぁ、言語仕様的にはOKという事で・・・。

maki_maki_
質問者

補足

早々のご回答有難うございます。 taka451213さんのお考えでは、 インタフェースがもつ抽象メソッドの定義は、インタフェースを実装しているクラス、またはそのスーパークラスかサブクラスのどこかにあれば良いということですね。 このとき、1つだけ引っかかったのがインタフェース型の変数というものです。このインタフェースを実装したクラス、またはこのクラスのサブクラスのオブジェクトは、このインタフェース型の変数で扱うことが多いと思いますが、その場合、どのように抽象メソッドの定義を見つけるのかをどのように理解したらよいのか分からなくなります。 もし、メソッドのオーバーライドの要領で、スーパークラス(インタフェース)に宣言されているメソッドを実行しようとしたら、サブクラス(インタフェースが実装されたクラス、またはこのクラスのサブクラス)で宣言されている同じメソッドが実行されるとは、考えることができなくなりそうです。 そこで、もつ1つ質問させてください。 インタフェース型の変数を用いた場合の、メソッドの宣言の見つけ方は、メソッドのオーバーライドの場合とは別物なのでしょうか? Javaの仕様書に目を通してみていますが、これに関する記述が見当たらなくて・・・。 細かい質問で申し訳ありませんが、何か情報ありましたらお知らせください。

関連するQ&A

  • 抽象クラスからオーバーライドについて

    EclipseでJavaを勉強始めました。 抽象クラスからオーバーライドするところで質問致します。 抽象クラスとして、「面積を計算する」というメソッドをもつDiagramクラスを定義しました。それを継承して、「四角形の面積を計算する」というメソッドをもつSquareクラスと、「三角形の面積を計算する」というメソッドをもつTriangleクラスを定義しました。 Squareクラス、Triangleクラスからインスタンスを生成して、四角形、三角形の面積をコンソールに表示させるという簡単なプログラムです。 このとき、main関数と3つのクラスの関係についてお尋ねします。 (1)iagram.java、Square.java、Triangle.javaそれぞれにクラス定義とmain関数を持たせるパターン public abstract class Diagram { // 面積計算定義(抽象メソッド) public static void main(String[] args) { } } public class Square extends Diagram{ //四角形の面積の計算定義 public static void main(String[] args) { //四角形の面積の計算と表示 } public class Triangle extends Diagram{ //三角形の面積の計算定義 public static void main(String[] args) { //三角形の面積の計算と表示 } (2)sample.javaというファイルにまとめ、その中にこの3つのクラス定義とmain関数を一つ持たせるパターン public class sample { public static void main(String[] args) { //四角形の面積の計算と表示 //三角形の面積の計算と表示 } } abstract class Diagram { // 面積計算(抽象メソッド)定義 } class Square extends Diagram{ //四角形の面積の計算定義 } class Trapezoid extends Diagram{ //三角形の面積の計算定義 } この二通りを考えて、どちらも実行できたのですが、どちらの方がJavaらしいプログラムと思われますでしょうか?

    • ベストアンサー
    • Java
  • 抽象メソッド、抽象クラス

    C#を勉強しております。Javaにも同じ機能がありC#のカテゴリーがない為こちらで質問させていただきます。抽象メソッドや抽象クラスを使う利点に関してです。 これらを使う利点を調べたところオーバーライドさせられると書いてありました。オーバーライドしないと 実装がないのでエラーになると書いてありました。その点は理解できたのですが何故基本クラスで実体のない定義をする利点がよくわかりません。それなら最初から派生クラスの方にメソッドを定義すればいいのではという考えになりました。 抽象メソッドとして実体のない定義を行う利点なるものを教えてください。 よろしくお願いします。

  • インターフェイスと抽象クラス

    なかなか理解が難しくて苦しんでいます。 で自分なりに理解したのですが、 抽象クラス→内容に決まっているメソッドと決まっていないメソッドがある場合に決まっていないメソッドを あとからオーバーライドするだけでスーパークラスで定義したすべてのメソッドを利用できる。 これでただしいでしょうか? で、インターフェイスなのですが、この抽象クラスとそっくりなんですが、 (1)変数は定数になる(強制static)(2)メソッドは名前のみの宣言(内容は記述できない) と言うことで、かなり???なのです。 何のために・・・???記述するんでしょうか?? ただひとつメリットがあるとしたら、インターフェイスを実装すると、インターフェイスの配列でインスタンスを 生成出来るということぐらいでしょうか。 そこでちょっとお門違いの疑問かもしれないんですが、 Runnable、やMouselistenerはメソッドの内容が書かれていないのに、 なぜ機能を持たせることが出来るのでしょう??? 認識違い、間違い等ありましたら、教えてください よろしくお願いいたします。

    • ベストアンサー
    • Java
  • アブストラクトとインターフェースの簡単な一例文

    JAVAについて質問よろしくお願いします。 abstract抽象クラスとインターフェースについて下記理解なのですが、超かんたんな一例など欲しいのですが何かないでしょうか。たとえば package round1.chapter1; public class Helloworld { public static void main(String[] args) { System.out.println("こんにちは!"); } } というような一文です。 ~私の理解~ アブストラクトとは、違ったクラス内で同一メソッドがある場合は親クラスに置き、違ったメソッドがある場合は抽象クラスとして親クラスに置いて、実装はサブクラスに任せるという形式で使われる言葉 インターフェースとは、機能だけを仕様書として書いておき、定義されたとおりのメソッドを実装しないといけないという呼び出し方の統一を図る際に使われるメソッド置き場 ~~~~~ このふたつについてものすごく簡単な使用例を頂きたいです。 よろしくお願いいたします。

    • ベストアンサー
    • Java
  • オーバーライドの必要性

    まだまだJavaを勉強している途中なのですが、下記のサンプルコードでオーバーライド(メソッドをオーバーロードすることをオーバーライドというのでしょうか…!?)のの必要性がよく分からなくなってしまったので質問させて頂きました。 /* sample.java */ abstract class super_class{  void write(){} } class CLASS1 extends super_class{  void write(){ System.out.println("CLASS1"); } } class CLASS2 extends super_class{  void write(){ System.out.println("CLASS2"); } } class sample{  public static void main(String args[]){   super_class obj = new CLASS2();   obj.write();   obj = new CLASS1();   obj.write();  } } 以上のコードを実行した場合 CLASS2 CLASS1 と表示されるのは多少なりとも勉強して分かったつもりでした…。 しかし、あくまでサンプルであるために特に意味がないことでもオーバーライドの説明をしているのだろうという風に考えてしまったのですが、 結局は、 スーパークラスとサブクラスに同じシグネチャのメソッドがあった場合、各サブクラスのメソッドが実行される と言うことは、スーパークラスのwrite()メソッドは何をしているのでしょうか? 多様性はJavaでも大切なものであるとのことなので質問させて頂きました。 なるべくわかりやすく説明して頂きたいと思います。 どうかお答えをお願いします。

    • ベストアンサー
    • Java
  • インターフェイスと抽象メソッドについてお願いします。

    PHPの参考書で「抽象メソッド」と「インターフェイス」それに「実装」という言葉が出てきました。 プログラミングが初めてで全然理解できなく困っています。 ・抽象メソッド ・インターフェイス ・実装 上記の意味とメリットなどを教えてください。それとどのような面で使うのかも教えていただけると嬉しいです。 すみませんが、よろしくお願いします。

    • ベストアンサー
    • PHP
  • インターフェイス実装クラスの表示について

    /* インタフェースPlanetを実装したクラスEarth、Marsがあります。  以下の実行結果になるようにクラスAggregateへshowメソッドを  追加してください。 [実行結果] 地球 太陽系にある惑星の1つで、太陽から3番目に近い。・・・ 火星 太陽系の太陽に近い方から4番目の惑星である。・・・ */ // [Planet.java] // 実装したいPlanetクラス interface Planet {   public String getName();   public String getOutline(); } // Planetを実装したEarthクラス // [Earth.java] class Earth implements Planet {   private final String name="地球";   // getNameメソッド:戻り値String、引数無し   public String getName(){    return name;   }   // getOutlineメソッド:戻り値String、引数無し    public String getOutline(){      return "太陽系にある惑星の1つで、太陽から3番目に近い。・・・";    } } // Planetを実装したMarsクラス // [Mars.java] class Mars implements Planet {   private final String name="火星";   // getNameメソッド:戻り値String、引数無し   public String getName(){     return name;   }   // getOutlineメソッド:戻り値String、引数無し   public String getOutline(){     return "太陽系の太陽に近い方から4番目の惑星である。・・・";   } } // メインクラス // [Main.java] class Main{   public static void main(String[] args){   // Earth&Marsクラスのインスタンス化    Earth earth = new Earth();     Mars mars = new Mars();   // Aggregateクラスのインスタンス化   Aggregate aggregation = new Aggregate();   // showメソッド呼び出し:戻り値無し、引数earth・mars    aggregation.show(earth);    aggregation.show(mars); } } // [Aggregate.java] class Aggregate { // ここにshowメソッドを追加   public void show(Earth planet){     System.out.println();   }   public void show(Mars planet){     System.out.println();   }  } showメソッドに引数としてEarth planet,Mars planetを渡すというところまでは理解しています。後は星の名前と概要を表示するのですが、例えば、 showメソッド内 // ここにshowメソッドを追加 public void show(Earth planet){ String str = earth.getName(); System.out.println(str); } public void show(Mars planet){ String str2 = mars.getOutline(); System.out.println(str2); } } とすると、erathとmarsの部分が「シンボルがありません」のエラーになります。自分の認識としては、EarthクラスとMarsクラスでフィールド変数を宣言しているので使えるのでは?と思っていたのですが、全然違うようです。どなたかどちらかのコード例を表記して頂けないでしょうか?よろしくお願い致します。

    • ベストアンサー
    • Java
  • 抽象クラスとインターフェースの使い分け

    抽象クラスとインターフェース、この2つの違い、使い分け方が未だにはっきりとはわかりません・・・ 抽象クラスもインターフェースも実装は持たず、抽象クラスはサブクラスで、インターフェースはそれをインプリメントしたクラスで実装を行うのですよね? 両者ともに言わば中身はなく外枠だけ定義されていると言えると思うのですが、だとしたらこの2つの違いや使い分けってどうなるのでしょうか。 抽象クラスでは部分的な実装を含められることや、インターフェースでは実装クラスが全てのメソッドを実装しなければいけない、複数実装できるといった使い方の違いしかないのでしょうか。 だとしたら実際に抽象クラスとして用意するのかインターフェースとして用意するのかの選択基準はなんなのでしょうか。 明確にこういう場合は抽象クラス、こういう場合はインターフェースなどと言った使い分けってあるのでしょうか。

  • インターフェース

    インターフェースについて学ぼうと思っているのですが、 どうもいまいち何がなんだかわからなくなっています。 インターフェースはクラスによって実装され、 実装クラスはインターフェースで宣言されている 抽象メソッドを実行する とあるのですが、実装とは何ですか? 抽象メソッドとは何ですか?

    • ベストアンサー
    • Java
  • メソッドのオーバーライド(java)

    class A3{ void hello(){ System.out.println("A3"); } void hello(int i){ System.out.println("A3"+i); } } class B3 extends A3{ void hello(){ System.out.println("B3"); } } class C3 extends B3{ void hello(String s){ System.out.println("C3"+s); } } class MethodOverriding3{ public static void main(String args[]){ A3 obj = new C3(); obj.hello(); } } 上のプログラムを実行すると"B3"と表示されまが、どうしてクラスBのメソッドが実行されるのでしょうか? クラスAのメソッドが無視される仕組みがわかりません。 また、クラスMethodOverriding3でobj.hello("abc")としてコンパイルすると mo.java:25: シンボルを見つけられません。 シンボル: メソッド hello(java.lang.String) 場所 : A3 の クラス obj.hello("abc");   ^ エラー 1 個 とエラーが出ます。 どうしてでしょうか? 誰か教えてください、お願いします。

    • ベストアンサー
    • Java

専門家に質問してみよう