「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」は正しい?
はじめまして。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
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にあっても問題ないことが分かると思います。
salsberryさん
的確なご回答有難うございました。
頂いたキーワードinvokevirtualとinvokevirtualからVMの仕様書に辿りつきました。
The JavaTM Virtual Machine Specification
http://java.sun.com/docs/books/jvms/second_editi …
仕様書内では、インタフェース型の変数を用いた場合のメソッドの検索手順とクラス型の変数を用いた場合のメソッドの検索手順が明確に記述されていました。細かな違いはあるものの、ほぼ同じ手順で検索されていること、またその手順そのものが分かりました。
salsberryさんのご指摘通りで、メソッドの探索は、末端のサブクラスからスーパークラスの方へ向って行われるんですね。
結果的に、インタフェースの抽象メソッドの実体は、インタフェースが実装されているクラスの前後どこかにあれば良いとなりますね。
有難うございました。
No.5
- 回答日時:
こんにちは。
補足、拝見しましたが・・・、
ちょっと質問の意味がわかりかねます。
どのようなところが疑問なのでしょう?
例えば・・・、で結構ですので、補足して頂けますか?
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
No.4
- 回答日時:
確認したいことがあります.
「もし、メソッドのオーバーライドの要領で、スーパークラス(インタフェース)に宣言されているメソッドを実行しようとしたら、サブクラス(インタフェースが実装されたクラス、またはこのクラスのサブクラス)で宣言されている同じメソッドが実行されるとは、考えることができなくなりそうです。」
というのは, どういうことでしょうか? 基本的には同じようにメソッドを検索するような気がするのですが....
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で実装してあれば、継承先でもそのメソッドを実装している事になります。
yossy_sas2000さん
ご回答有難うございました。
>抽象メソッドの定義(インタフェースの実装)を前に書くか後に書くかは、関係ありません。
この点に関するホームページを紹介して頂き有難うございます。確認することができました。
No.2
- 回答日時:
#1 と同じなんだけど, 結局
・インターフェイスX を実装する具象クラスは void show() を持っていなければならない
・クラスB は (クラスA から継承した) void show() を持っている
ので大丈夫, と.
この回答への補足
早々のご回答有難うございます。
Tacosanさんのお考えも、taka451213さんと同じようですね。
taka451213さんへ再度質問させて頂きましたが、インタフェース型の変数で、そのインタフェースがもつ抽象メソッドへアクセスした場合に、どのように実際のメソッドの定義を見つけるのかについて何かご存知でしたらお知らせお願いします。
質問内容は、taka451213さんへの補足をご参照頂ければと思います。
No.1
- 回答日時:
こんばんは。
特に不思議ではないですが・・・?
クラスBはクラスAをextendsしているので、interface Xをimplementsするための要件は満たしています。
ただ、このimplementsをBに書くのに違和感を感じますが・・・。
まぁ、言語仕様的にはOKという事で・・・。
この回答への補足
早々のご回答有難うございます。
taka451213さんのお考えでは、
インタフェースがもつ抽象メソッドの定義は、インタフェースを実装しているクラス、またはそのスーパークラスかサブクラスのどこかにあれば良いということですね。
このとき、1つだけ引っかかったのがインタフェース型の変数というものです。このインタフェースを実装したクラス、またはこのクラスのサブクラスのオブジェクトは、このインタフェース型の変数で扱うことが多いと思いますが、その場合、どのように抽象メソッドの定義を見つけるのかをどのように理解したらよいのか分からなくなります。
もし、メソッドのオーバーライドの要領で、スーパークラス(インタフェース)に宣言されているメソッドを実行しようとしたら、サブクラス(インタフェースが実装されたクラス、またはこのクラスのサブクラス)で宣言されている同じメソッドが実行されるとは、考えることができなくなりそうです。
そこで、もつ1つ質問させてください。
インタフェース型の変数を用いた場合の、メソッドの宣言の見つけ方は、メソッドのオーバーライドの場合とは別物なのでしょうか?
Javaの仕様書に目を通してみていますが、これに関する記述が見当たらなくて・・・。
細かい質問で申し訳ありませんが、何か情報ありましたらお知らせください。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- Java javaの質問です 次の機能を有するメソッド4つを自クラスに作成し、実装したいです 【機能】 足し算 1 2022/06/15 17:49
- Java java 次の機能を有するメソッドを自クラスに作成し、実装したいです。 機能 名前判定機能 →名前が 3 2022/06/16 16:08
- Java javaのクラスの分け方について質問です。 APIの内部用と外部用でクラスを分けたいのですがインター 2 2022/04/26 16:06
- その他(プログラミング・Web制作) pythonのプログラムについての質問です。 1 2023/05/26 10:31
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- Java javaの質問です 次の機能を有するメソッド4つを自クラスに作成し、実装したいです 【機能】 足し算 1 2022/06/15 15:14
- その他(プログラミング・Web制作) どういうプログラムで組みますか?google colabでやってるんですけど、出来る方お願いします。 1 2022/07/17 18:41
- Java java final 1 2022/06/10 22:49
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
レコード件数の表示
-
Java初心者です、エラーの意味...
-
コマンドライン引数のチェック
-
String.containsの反対機能はあ...
-
なぜprotected overrideなのか
-
javaに"search"という関数 or ...
-
Java初級 引数に適用できません
-
public static void main (Stri...
-
Google Apps Script で getRang...
-
C# 点の描き方をおしえてくだ...
-
javaのprivateって?
-
実行画面で表示されるエラーの...
-
メソッドの引数に指定されてい...
-
メソッドの書き方
-
Strutsでチェックボックスの値...
-
親の親のメソッドを呼ぶには?
-
継承とオーバーライド
-
「タイプ初期化子が例外をスロ...
-
javaのコンパイルができません...
-
エクセルVBAで、条件に一致する...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Java初級 引数に適用できません
-
String.containsの反対機能はあ...
-
なぜprotected overrideなのか
-
Strutsでチェックボックスの値...
-
Google Apps Script で getRang...
-
abstract と static を一緒に付...
-
C# 点の描き方をおしえてくだ...
-
レコード件数の表示
-
public static void main (Stri...
-
StringBufferからStringへキャ...
-
YYYYMMDD書式の日付に対する適...
-
C# でメソッドに送られてきたOb...
-
シェルスクリプトからのJavaメ...
-
C# の ByVal と ByRef について
-
Fileの読み取り専用の解除
-
CSVから読み込んだデータの保持...
-
メソッドの引数に指定されてい...
-
javaに"search"という関数 or ...
-
Javaのメモリの管理
-
Java初心者です、エラーの意味...
おすすめ情報