質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

6回答

7942閲覧

java:オーバーライドの際、staticメソッドに変更してはいけない理由について

karakorum

総合スコア20

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

3クリップ

投稿2020/08/30 04:16

親クラスを継承した子クラスで、親クラスのインスタンスメソッドをオーバライドする際、いくつかのルールがあると思うのですが、その中で「インスタンスメソッドをstaticメソッドに変更してはいけない」というルールがどうしても腑に落ちません。

まず、正しいオーバーライドの構文を書きます。
下記ソースコードでは、SuperClassクラスを継承したSubClassクラスがSuperClassクラスで宣言しているmethodメソッドをオーバーライドしています。
そして、mainメソッドでSubClassクラスのインスタンスを生成し、インスタンスのアドレス値をSuperClassクラス型に暗黙変換し、sup変数に代入しています。
そして、SuperClass型のインスタンスのアドレス値が指すインスタンスのmethodメソッドを呼び出すと、オーバーライドのルールより、子クラスのメソッドが呼び出されるため、出力結果としては、「子クラス」と出ます。

public class Sample{ public static void main(String[] args){ SuperClass sup=new SubClass(); sup.method(); } } class SuperClass{ public void method(){ System.out.println("親クラス"); } } class SubClass extends SuperClass{ public void method(){ System.out.println("子クラス"); } }

ここからが疑問なのですが、
下記のようなソースコードを書くとメソッドのオーバーライドをしてる部分でコンパイルエラーとなります。理由としてはオーバーライドするメソッドのstatic修飾子を変更しているからです。それは分かるのですが、なぜ、staticなメソッドに変更してはいけないのでしょうか?
確かにインスタンスメソッドをstaticメソッドに変更することに違和感があると直感的には分かるのですが、いまいちピンときません。
また、今回のメソッドに関しては非staticメンバ変数を参照していないので、インスタンスメソッドでも非staticメソッドでも、機能面に異常はないように思えます。
ここの部分を詳しく教えていただける方がいましたら、よろしくお願いします。

public class Sample{ public static void main(String[] args){ SuperClass sup=new SubClass(); sup.method(); } } class SuperClass{ public void method(){ System.out.println("親クラス"); } } class SubClass extends SuperClass{ public static void method(){ System.out.println("子クラス"); } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

なぜ、staticなメソッドに変更してはいけないのでしょうか?

以下のようなコードを考えてみましょう。

java

1SuperClass sup = new SubClass(); 2sup.method();

SuperClassではmethodがインスタンスメソッドなのでコンパイルを通りますが、仮にSubClassstaticなメソッドになっていたとしたら、sup.method()のようにインスタンスから呼ぶことができなくなってしまいます。

これでは「スーパークラスの型でサブクラスを扱う」ことができなくなってしまうので、メソッドの呼び方が変わるような、staticと非staticを切り替える形のオーバーライドはできません。

投稿2020/08/31 11:47

編集2020/08/31 11:51
maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/08/31 11:53

余談ですが、RubyやES6以降のJavaScriptなど、「クラスメソッド=クラスオブジェクトに追加するメソッド」という言語の場合、同じ名前のクラスメソッドとインスタンスメソッドが共存できます(継承関係で追加しても単なる追加になるだけで、オーバーライドになりません)。
karakorum

2020/09/06 22:05

ご回答ありがとうございます。 つまり、インスタンスメソッドからstaticなメソッドは使えない、逆もまた然り。なので、ポリモフィズムを実現するために存在するオーバライドにおいて、static修飾子を変更することは許されていない、ということなんですね! ありがとうございます!
guest

0

ベストアンサー

staticメソッドは、どのメソッドが呼ばれるかがコンパイル時に静的に決まります。
そういう性質を与えられているから、staticと呼ばれているのです。

https://eow.alc.co.jp/search?q=static&ref=sa

質問のコードのsup.method()の部分は、どのメソッドが呼ばれるかが実行時に動的に決まる部分です。(SuperClass#methodが動的なメソッドですから)
その部分のコードが実行される時にstatic修飾が付いたメソッドが呼ばれる可能性があるなら、それはstaticという名前に反するわけです。

実行時に動的に呼び出し先が決まるのではなく、コンパイル時に静的に呼び出し先が決まるメソッドだからstaticという名前が付いているのです。
「インスタンスフィールドにアクセスしないからstaticメソッドでも機能面に異常はない」という考えは順序が逆なのです。
「コンパイル時に静的に呼び出し先が決まるという機能を持ったメソッドが欲しいから、そのためにはインスタンスフィールドにアクセスしてはならない」という順序なのです。

投稿2020/08/31 07:23

編集2020/08/31 11:38
quickquip

総合スコア11038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karakorum

2020/09/06 22:32

ご回答いただきありがとうございます。 static修飾子について考えた時、確かにルールに反すると思いました。 その観点から行くと、static修飾子の変更はコンパイルエラーになりますね。 腑に落ちました! ありがとうございますした!
guest

0

どちらもメソッドであると言うだけで、全く違う物だからとしか言いようが無いです。

変更したいという気持ちが出てくるとしたら、
・クラスの設計が間違っていた
・そもそも何も分かっていない
のどちらかだと思います。

投稿2020/08/30 06:07

otn

総合スコア84555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karakorum

2020/08/30 06:38

回答いただき、ありがとうございます。 ・クラスの設計が間違っていた ・そもそも何も分かっていない →確かにオーバーライドの際、わざわざstaticなメソッドにする動機はないと思います・・・。 ただ、機能的にできてもいいんじゃないかなー?と思い質問をしました。 確かにクラスとインスタンス自体別物、という認識はあるのですが、コンピュータ目線で見ると、メソッドをstaticなメソッドとして再定義しても、メソッドを特定できそうな気がしたので疑問に思っていました。
guest

0

オーバーライドができない理屈については他の回答や教科書を参照してもらいたいですが、「ダメな理由探し」をしたいのであれば

また、今回のメソッドに関しては非staticメンバ変数を参照していないので、インスタンスメソッドでも非staticメソッドでも、機能面に異常はないように思えます。

「今回」と言っているので自覚があると思いますが、非staticなメンバ(インスタンスメンバ)を参照していたらオーバーライドが不可能だという事はわかっているんですよね?

であれば、そもそも派生元のメソッドの中身次第でオーバーライドの可否が決まるのが、正しい言語設計だと思いますか?

また、当初は非staticメンバへの参照がなかったとして、派生元が修正されて非staticなメンバを参照することになった場合にどうなると思いますか?

「非staticメンバ変数を参照していない」というのはあくまで「現時点では」という話ですよね。将来的にもそれが保証されることがありえますか?目の前のコードだけでなく、世界中のすべてのコードで。無理ですよね。

「非staticメンバ変数を参照していない」→「非staticメンバ変数を参照している」への変更があった場合、この継承関係は破壊されます。

派生先の外部設計が変更されたのならまだしも、内部のメソッドの記述が変わるだけで継承関係を壊すような事になるのはおかしいと思いませんか?

オブジェクト指向は属性(プロパティ)と振る舞い(メソッド)に基づいているわけで、実際のメソッド内の処理がどのようなものであれ、外側から見たメソッドには何の変更もないのに、継承関係が壊れるというのはそもそもあってはなりません。

投稿2020/08/31 08:24

gentaro

総合スコア8949

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karakorum

2020/09/06 22:33

確かに今回はたまたま、非staticなメンバを参照していないだけで、今後どうなるかは分からないですね。 その観点からいくと、確かにstatic修飾子の変更はダメなことだと思いました。 ありがとうございます。
guest

0

see: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8

8.4.8.1. Overriding (by Instance Methods)
...
It is a compile-time error if an instance method overrides a static method.

投稿2020/08/30 05:13

編集2020/08/30 05:13
shiketa

総合スコア3971

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karakorum

2020/08/30 07:03 編集

ご回答ありがとうございます。 該当箇所を読み込み、javaのリファレンスでも非staticなメソッドをstaticなメソッドに変更してオーバーライドすることは禁止とされているということは理解しました。 ただ、理由に関していまいちピンとくる箇所がなく、教えていただいたサイトを読み解いていこうと思います。 ありがとうございます。
guest

0

そもそもstaticはインスタンスにひもづかないので、オーバーライドする/されるようなものじゃないです。

以下は、コンパイルエラーが出なくなりますが、想定と異なる動きじゃないでしょうか?
※想定と異なる=オーバーライドされない

java

1public class Sample { 2 public static void main(String[] args) { 3 SuperClass sup = new SubClass(); 4 sup.method(); // 警告 static メソッドのアクセス方法 5 } 6} 7class SuperClass { 8 public static void method() { // static を追加 9 System.out.println("親クラス"); 10 } 11} 12class SubClass extends SuperClass { 13 public static void method() { 14 System.out.println("子クラス"); 15 } 16}

投稿2020/08/30 06:13

momon-ga

総合スコア4820

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karakorum

2020/08/30 06:40

ご回答いただきありがとうございます。 そもそもオーバーライドのルール的にインスタンスの持ち物である非staticなメソッドしか対処としていない。だから、クラスの持ち物であるstaticなメソッドが出てきたらコンパイルエラーとなる、といった認識でしょうか?
xebme

2020/08/31 07:51

オーバーライドされないのならポリモーフィズムが働かない。static メソッドは定義したクラスの型でしか実行できません。一方、ポリモーフィズムはスーパークラスの型で機能します。この点を深く考えてみませう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問