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

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

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

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

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

Q&A

解決済

4回答

1764閲覧

Java ポリモーフィズムについて

orange3

総合スコア6

Java

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

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

0グッド

3クリップ

投稿2020/03/21 07:24

前提・実現したいこと

Java Silverの試験の勉強をしています。
実務経験は一切ありません。
日本サード・パーティ株式会社作成の問題集をやって、学習していますが、調べてもわからないことが出てきたので、
こちらに質問させていただきます。
実現したいことは、私の認識があっているかを確認することです。

問題文とその回答

問題文:このコードをコンパイル、および実行すると、どのような結果になりますか。一つ選択してください。
A. N67-10
B. Gold
C. SnackPine
D. null
答えはDのようです。 私はCだと思いました。

該当のソースコード

Java

1class Fruits{ 2 protected String name; 3 protected static Fruits fruits; 4 Fruits(){ 5 fruits = this; 6 } 7 protected String getName(){ 8 return fruits.name; 9 } 10} 11class Painapple extends Fruits { 12 protected String name; 13 Painapple(String name){ 14 super.name = name; 15 } 16 protected String getName(){ 17 return this.name; 18 } 19} 20class Test extends Fruits{ 21 public static void main(String args[]){ 22 Fruits fruits = new Painapple("N67-10"); 23 fruits.name = "Gold"; 24 fruits.fruits.name = "SnackPine"; 25 System.out.println(fruits.getName()); 26 } 27} 28

私の理解

この場合、変数fruitsの型はFruitsでインスタンスはPainapple型で作成しているため、
ポリモーフィズムが関わる問題だと認識しております。
なので、 fruits.name = "Gold";でGoldが代入されるのはclass Painapple extends Fruitsにて定義したnameだと思いました。
fruits.fruits.name = "SnackPine";についても同様で、
ポリモーフィズムの考え方からサブクラスであるPainappleクラスのname変数に代入されると思いました。

ただ、問題集の解説文だと、Fruitsクラスのname変数に代入しているとのことです。
なので、解説文によるとPainappleクラスのname変数には何も入らずに、結果的にNullが表示されるとのことです。

私のポリモーフィズムの理解は、
継承するクラスにおいて同じ名前で同じ修飾子がついてる場合、
スーパークラスにおいて定義されたメソッドや変数は呼び出されず、
基本的に継承したクラスにおいて定義したメソッドや変数が呼び出される。
仮にスーパークラスでの定義したものを呼び出したければsuper.(メソッド名、変数名)が必要だということです。

すみません、初めての投稿でして、いろいろとルールに則っていない部分もあるかもしれませんが、ご容赦ください。
以上よろしくお願いいたします。

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

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

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

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

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

guest

回答4

0

Zuishinさんが、さらっと最後に重要なことをいっているのですが。
大事なことなので、最初にいいます。

メソッドは、オーバーライドしますが、フィールドはオーバーライドされません!
以下は同じインスタンスをキャストしてフィールドとメソッドをアクセスするものです。

実行結果を確認してみてください。

java

1class Fruits { 2 protected String name = "Fruits"; 3 4 protected String getName() { 5 return "method1 " + name; 6 } 7} 8 9class Painapple extends Fruits { 10 protected String name = "Painapple"; 11 12 protected String getName() { 13 return "method2 " + name; 14 } 15} 16 17public static void main(String args[]) { 18 Fruits fruits = new Painapple(); 19 System.out.println("Fruits field:" + fruits.name); 20 System.out.println(fruits.getName()); // Override 21 22 System.out.println(); 23 System.out.println("class cast"); 24 25 System.out.println("Painapple field:" + ((Painapple)fruits).name); 26 System.out.println(((Painapple)fruits).getName()); 27}

で、今回の場合ワナがいっぱいありまして・・・
まず。Painappleに同名のフィールドnameが存在しているが、実際にはアクセスされない。(型がFruitsのため)
Painappleのコンストラクタでnameが設定されるのは、super.name。
Painapple#getName()で、戻されるのはPainappleのname(未設定のためnull)

投稿2020/03/23 02:54

momon-ga

総合スコア4826

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

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

orange3

2020/03/24 03:36

確認用のソースコードまで誠にありがとうございます。フィールドについては、オーバーライドされないため、型の中で定義されたものにアクセスされるということで理解致しました。
guest

0

ベストアンサー

main から実行を開始します。

new Painapple("N67-10"); により Painapple のインスタンスができます。

その Painappleインスタンスには、3つのフィールドがあります。
・static の fruits = null
・Fruits の name = null
・Painapple の name = null

コンストラクタFruits() が呼び出されれて、fruits = this; により
・static の fruits = Painappleインスタンス

コンストラクタPainapple() が呼び出されて super.name = name; により
・Fruits の name = "N67-10"

main に戻って、Fruits fruites = により
・main の fruits = Painappleインスタンス

fruits.name = "Gold"; により
・Fruits の name = "Gold"
なぜなら、fruits は Painappleインスタンスで、Painapple は 2つの name を
持っているが、フィールドはオーバーライドされないから。

fruits.furits.name = "SnackPine"; により
・Fruits の name = "SnackPine"
なぜなら、fruits.fruits は Painappleインスタンスで、Painapple は 2つの
name を持っているが、フィールドはオーバーライドされないから。

fruits.getName() は、メソッドなのでオーバーライトされた Painapple の
getName() が呼び出され、Painapple の name = null が返ってくる。

Painapple(苦痛のリンゴ) は Pineapple(パイナップル)にして欲しかった。

追記
fruits.name = "Gold"; を
((Painapple)fruits).name = "Gold" に変更すると、
・Painapple の name = "Gold"
なぜなら、main の fruits は Fruitsへの参照型であるが、それを
Painappleへの参照型にキャストしたので、「Painapple の name」になるから。
最後の println で "Gold" が表示される。

また、fruits.fruits.name = "SnackPine" を
((Painapple)fruits.fruits).name = "SnackPine" に変更すると、
・Painapple の name = "SnackPine"
なぜなら、fruits.fruits は static の fruits であり、これは Fruitsへの
参照型であるが、それを Painappleへの参照型にキャストしたので、
「Painapple の name」になるから。
最後の println で "SnackPine" が表示される。

ところが、fruits.fruits.name = "SnackPine" を
((Painapple)fruits).fruits.name = "SnackPine" に変更すると、
・Fruits の name = "SnackPine"
なぜなら、main の fruits を Painappleへの参照型にキャストしても Painappleの
fruits は「static の fruits」であり、それは Fruits への参照型だから。
最後の println で null が表示される。

投稿2020/03/21 12:25

編集2020/03/21 23:37
kazuma-s

総合スコア8224

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

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

orange3

2020/03/24 03:30

追記の説明も誠にありがとうございます。フィールドはオーバーライドされないため、仮に派生型のフィールドを引用したい場合、明示的にキャストしてあげる必要があるということですね。 >>Painapple(苦痛のリンゴ) は Pineapple(パイナップル)にして欲しかった。 実は参考書でもこの綴りでの記載だったんですよね。。なので、参考書の信ぴょう性を疑ってしまいました。
guest

0

次の実行結果を見てください。

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

結果はこうなっています。

フルーツ パイナップル フルーツ

1 番目は Fruit 型のオブジェクトを Fruit 型の変数に入れています。
2 番目は Pineapple 型のオブジェクトを Pineapple 型の変数に入れています。
3 番目は Pineapple 型のオブジェクトを Fruit 型の変数に入れています。

Fruit 型とその派生型である Pineapple 型はそれぞれインスタンス変数 name を定義しています。これにより、Pineapple 型の name が Fruit 型の同名の変数 name を隠蔽します。
しかし、Pineapple 型のオブジェクトを Fruit 型の変数に入れたとき、すなわち Pineapple 型を Fruit 型にキャストした時、その name 変数は Fruit 型のものを指します。

オーバーライドされた場合には、キャストされた後でも派生型のメンバーを指しますが、変数はオーバーライドできません。詳しくは隠蔽とオーバーライドの違いを調べてください。

投稿2020/03/21 09:26

Zuishin

総合スコア28669

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

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

orange3

2020/03/24 03:17

ご説明誠にありがとうございます。”オーバーライドされた場合には、キャストされた後でも派生型のメンバーを指しますが、変数はオーバーライドできません。”この一文が重要ですね、私の認識だと変数もオーバーライドされるものだと思っておりました。クリアになりました。ありがとうございます。
guest

0

私の認識があっているかを確認する

「あっていない」から答えが違ったのではないでしょうか.

投稿2020/03/21 08:31

jimbe

総合スコア13209

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

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

orange3

2020/03/21 08:44

質問の仕方が悪かったです。失礼しました。今回の問題において、fruits.name = "Gold";がFruitsクラスのname変数を指すのはなぜでしょうか。
jimbe

2020/03/21 08:51

fruits が Fruits だからだと思います. 予想と現象が一致しない場合, 現象が間違っているとは出来ないのですから, 予想の元になった理解(?)を修正するしかありません. 「理解」をどう修正すればこの現象に一致するのかは, 「問題集の解説文」やご提示のコードを弄ってみる等で調査出来るかと思います.
orange3

2020/03/24 03:14

勉強の姿勢についてご指摘いただき、誠にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問