• ベストアンサー

オブジェクト・・・参照代入・・・???

問題(1) class ApBase extends Object implements Runnable (省略) ApBase aBase = new ApBase(); Runnable aR = aBase; ○ オブジェクトにインターフェースが実装されていることがわかる限りオブジェクト参照をインターフェイス参照に 代入することは可能です。 問題2 class ApBase extends Object implements Runnable (省略) Object obj = aBase; Runnable rn = obj; × コンパイラにとってobjはObjectなのでRunnnableインターフェイス参照への代入は認められません。 同じほんの問題です。 矛盾していませんか??? ・・・・多分僕の理解が足りないだけです(^_^;) もう少しわかりやすく教えてください・・・ お願いいたします

  • Java
  • 回答数3
  • ありがとう数5

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

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

ApBase クラスは、Object クラスを継承していて、Runnable インタフェイスを実装していますね。 これは、ApBase のインスタンスは Object のインスタンスとして扱うことができるし、また Runnable のインスタンスとして扱うことができるということです。ApBase のインスタンスは Object のインスタンスでもあり、また Runnable のインスタンスでもある、と考えてもかまいません。 ですから、ApBase 型の変数である aBase を Runnable 型の変数である aR に代入できるわけです。 では問題2ではどうかというと、Object はどのクラスも継承していませんし、どのインタフェイスも実装していません。従って、Object のインスタンスはあくまでも Object であって、ほかのクラスやインタフェースのインスタンスとして振る舞うことはできないのです。 なので、Object 型の変数である obj を Runnable 型の変数である rn に代入することはできません。 ここで注意しないといけないのは、コンパイラがチェックしているのは変数そのものの型であって、実際に変数に代入されている(実行時の)中身の型ではないことです。(変数の中身の型が問題となるのは、実行時にキャストをするときです) 仮に問題2で obj に代入されているインスタンスが実際には ApBase 型であっても、obj を rn に代入することはできません。 つまり、こういうことです。 ApBase 型変数 aBase には、ApBase のインスタンスしか代入できないので、aBase の値も当然 ApBase のインスタンスである。 すると、aBase を obj に代入しても、obj に実際に代入される値はやはり ApBase のインスタンスとなる。つまり、Object 型変数 obj に、ApBase のインスタンスが入っていることになる。 しかし、たとえ ApBase が Runnable を実装していても、obj を rn に代入することはできない。なぜなら、obj はあくまでも Object 型であり、Object のインスタンスとして振る舞うからだ。 (これでもやっぱりわかりづらいかな……)

azicyan
質問者

お礼

じっくり読ませていただきました。 extends object とかいてあって、紛らわしいけれども あくまでもObjectは 独立したインスタンス(ApBaseとは関係なく)を生成する、 ということでよろしいでしょうか・・・ (^_^;) 自信なしです・・・

azicyan
質問者

補足

いつもいつもありがとうございます。 ちょっと難しいので、今印刷しました。 じっくり読んでから、 お礼をいたします。

その他の回答 (2)

  • kakuto
  • ベストアンサー率25% (1/4)
回答No.3

ApBase クラスは Object クラスを継承し、Runnable インタフェースを実装しているので Object オブジェクトや Runnable オブジェクトとして扱うことはできますが、 Object クラスは Runnable インタフェースを実装していないため Object クラスの派生クラスが必ずしも Runnable インタフェースを実装しているとは限らないので Runnable オブジェクトとして扱うことはできません。

azicyan
質問者

お礼

ありがとうございます。 勉強になります

  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.2

問題2の場合は、代入を認めてもいいと思うかもしれませんが、 たとえば(作為的な例だけど)以下のような場合困ります。 -------------- class ApBase extends Object implements Runnable{ ... Object obj = aBase; String str = "abc"; if(...)obj = str; Runnable rn = obj; --------------- ここでは、if(...)の判断によって、 objにはApBase型が入ったり、String型が入ったりします。 ApBaseだったらいいのですが、 String型の場合、Runnableとしては使えません。 他の言語、たとえばSmalltalkというプログラミング言語では、 こういった代入が自由にできて、実際にメソッドを起動するときにエラーが出ます。 そういうのもひとつの方法ですが、エラーを検出しにくいという欠点があります。 問題2で代入したいときには、 Runnable rn = (Runnable)obj; のようにキャストします。 実際にRunnable型と互換性のない型だった場合、ここでエラーが出ます。 Javaでは、型のチェックを厳密にすることによって、 エラーが起こりにくいように、 また検出しやすいようにしているわけです。

azicyan
質問者

お礼

もし ObjにString型を代入した時にRunnableに代入できないので、 キャストしなければ代入を認めない。 という理解で正しいでしょうか・・

azicyan
質問者

補足

いつも助かっています。 ちょっと難しいので印刷してじっくり読ませていただきます。 後ほどお礼いたします。 ありがとうございます

関連するQ&A

  • 参照代入

    class ApBase extends Object implements Runnable (省略) ApBase aBase = new ApBase(); Object obj = aBase; Runnable rn = obj; × コンパイラにとってobjはObjectなのでRunnnableインターフェイス参照への代入は認められません。 -----ー---- 以前質問させてもらった内容の一部なのですが・・・ 参照代入でコンパイルエラーを引き起こす場合 「is a」の関係が成り立っていない場合ですよね? なぜコンパイルエラーなのですか? Objectクラスはすべてのクラスのスーパークラスですよね・・・ Runnableとobjectはis aではないのでしょうか??????

    • ベストアンサー
    • Java
  • コンパイルエラー(Threadオブジェクト化)

    Runnableを継承したNormalClassをThreadとしてオブジェクト化しようとしているのですが、コンパイルエラーが出現して困っています。どうすればいいでしょうか? 下記エラー参照 Main.java:1: NormalClass は abstract でなく、java.lang.Runnable 内の abstract メソッド run() をオーバーライドしません。 下記ソース class NormalClass implements Runnable{ } class Main extends Thread{ public static void main(String args[]){ test = new Thread(new NormalClass()); } }

    • ベストアンサー
    • Java
  • Generics extends ObjectとObjectの違い

    初めて質問させていただきます。 Generics(extendsの?)の考え方についてです。 例えば、下記のような関数を作成したとします。 ======================================= public static String getHoge(Map<String , ? extends Object> checkMap){   Set<Map.Entry<String, Object>> checkMapKeySet = checkMap.entrySet();   ~ 処理 ~ } ======================================= 2行目で「型の不一致: Set<Map.Entry<String,capture#3-of ? extends Object>> から Set<Map.Entry<String,Object>> には変換できません。」とコンパイラから怒られます。 では、Objectの派生クラスをObjectとして扱えないのかと単純に理解しようとすると、以下のコードは普通にコンパイルできてしまいます。 ======================================= public static String getHoge(Map<String , ? extends Object> checkMap){   for(Map.Entry<String, ? extends Object> checkMapEntry : checkMap.entrySet()){     Object obj = checkMap.get("aa");     ~ 処理 ~   } } ======================================= 最初のコードがエラーになるなら、2つ目のコードの3行目(Object obj =の行)が何故エラーにならないのか、その違いをどのように解釈していいのか悩んでいます。 ご存じの方がいらっしゃいましたら、アドバイスでもいただけると幸いです。

    • ベストアンサー
    • Java
  • オブジェクトの参照を返す関数の扱い

    オブジェクトの作成と関数との関係を勉強していますが参照の使い方に関して質問させていただきたいと思います。 以下のような簡単なプログラムを作りました。 myclass.cpp myclass.h で記述されたクラスmyclassは整数を一つ持ち、show_value関数でその整数を表示し、say_heyで"hey"という文字を出力するというものです。 このクラスを利用するプログラムとしてmain.cppをつくりました。このなかには2つの関数が使われます。 -オブジェクトをつくりそれをオブジェクトとして返す関数(return_obj)   -オブジェクトをつくりそれの参照を返す関数(return_ref_obj) これらの関数を用いてオブジェクトをつくり、そのオブジェクトを戻り値としてmainのなかでオブジェクトのshow_value関数で保持する整数を表示する、というものです。 myclass.h-------------------------------- class Myclass{ public: int my_int; Myclass(); ~Myclass(); void show_value(); void say_hey(); }; myclass.cpp---------------------------------- #include "myclass.h" #include <iostream> using namespace std; Myclass::Myclass(){}; Myclass::~Myclass(){}; void Myclass::show_value(){ printf("%d\n", my_int); } void Myclass::say_hey(){ printf("hey\n"); } main.cpp------------ #include <iostream> #include "myclass.h" using namespace std; //オブジェクトをつくりそれをオブジェクトとして返す関数(return_obj)   Myclass return_obj(int int_in){ Myclass myobject; myobject.my_int = int_in; //引数をオブジェクトのmy_intに渡す return myobject; } //オブジェクトをつくりそれの参照を返す関数(return_ref_obj) Myclass& return_ref_obj(int int_in2){ Myclass myobject; myobject.my_int = int_in2;   //引数をオブジェクトのmy_intに渡す Myclass& ref_of_myclass = myobject; return ref_of_myclass; } void main(){ Myclass returned_obj = return_obj(1); //関数に1を渡し、1を保持するオブジェクトを作成 returned_obj.show_value(); //整数(1)表示 returned_obj.say_hey(); Myclass& ref_obj = return_ref_obj(2); //関数に2を渡し、2を保持するオブジェクトを作成し参照として受け取る ref_obj.show_value(); //整数(2)表示 ref_obj.say_hey(); } プログラムを実行した出力------------------- 1 hey -858993460 hey このようにオブジェクト自体を返してコピーしたもの(return_obj使用)はshow_valueでただしくオブジェクトに保持された数が表示されますが 参照でオブジェクトを返したもの(return_ref_obj使用)はアドレスのような数列が表示されます。 質問A これはオブジェクトの参照を返す関数(return_ref_obj)でオブジェクトを作成しても、そのオブジェクトが関数の中でのみ実在しており、関数がおわるとその実体がなくなるためではないかと解釈しているのですがそれで正しいでしょうか? 質問B 関数でオブジェクトを作成してそれをプログラム本体に渡すときはreturn_objのようにオブジェクト自体をコピーしなければ参照などで渡すことはできないのでしょうか? クラスと参照自体勉強を始めたばかりで色々と初歩的な間違いもあるとは思いますが、よろしくお願いします

  • System::Object へのmyClassの代入

    お世話になっております。 表題の件について困っております。お分かりになる方、教えてください。 やりたいことは、Windowsフォームアプリケーションで、ボタンやListBoxなどのコントローラにあるtagプロパティに自分で作ったクラス(MY_CLASS)のオブジェクトを代入したいのですが、やり方がわかりません。 オブジェクトクラスには何でも代入できると思っていたので普通に代入しようとるすと、 'MY_CLASS' から 'System::Object ^' に変換できません。 と怒られます。 どうすれば良いのかご教授ください。 お願いいたします。

  • PHPの参照渡しについて

    以下のようなコードがあったとき $obj = new stdClass(); $foo = $obj; この場合、動作は いわゆる【参照の値渡し】というとらえかたでよいのでしょうか? 変数$obj には、 new stdClass();という記述によって 新規に作成されたオブジェクトの参照(※正確には別のメモリ内に保持されたオブジェクトのアドレス) が保持されるわけですよね? そのとき $foo = $obj; というコードは$objが保持するオブジェクトのアドレス値を$fooという変数にも コピーするという動作を意味するわけですよね。 この場合、両変数を用いて生成されたオブジェクトのプロパティなどの状態を 共有することとができます。 しかしながら変数$fooに別の値、例えば文字列を代入すうると $foo = "文字列"; とすると$fooの値が変更され$objの値は変更されません。 対して、次のようなコードがあった場合 $foo = &$obj; というコード、これはPHPにおける参照渡しですが、 この場合は$objが指し示す、オブジェクトが保持されているメモリ上のアドレスではなく そのメモリ上に確保された変数$objそのもののアドレスが$fooという変数にコピー? されるのでしょうか? この明示的な参照渡しだと、オブジェクトの状態を共有するのはもちろん $foo = "オブジェクト破棄"; と片方に文字列を代入すると print $obj; 同様に文字列にかわってしまいます。 この本来の意味?であろう参照渡しとは実際 $fooに変数$objそのもののアドレスが保持されるという 解釈でよいのでしょうか? おくわしいかたご教授ください。

    • ベストアンサー
    • PHP
  • マルチスレッドの実装について

    只今、数冊の本を読み、現在マルチスレッドの部分を やっているのですが、 参考本AとBには class Sample extends Thread { というやり方が書いてあり、 参考本Cには class Sample implements Runnable { というやり方だけ書いてあります。 どういう事だと思い、クラスリファレンス本を読んでみると、 『マルチスレッドプログラミングを行う際にはthreadを継承するか、Runnableインターフェイスを実装します』 とだけ記述されていました。 参考本AとBは2002年に発行・改訂されており、「extends Thread」の説明しか載っていませんでした。 参考本Cは2000年発行で改訂はされていません。 Q:この2つは使い分けのようなものがあるのでしょうか?

    • ベストアンサー
    • Java
  • 派生クラスのメンバを基底クラスの参照に代入(C++

    文末のコードのように、 基底クラスで、派生クラスのメンバの参照を持つのはまずいでしょうか。 (classではなくstructにしているのは質問上でのpublic:の省略のためだけです) 初期化順序的には、基底クラスの参照先は、 基底クラスのコンストラクタが走る時点で初期化されていないので、 コンストラクタ内で参照に対して何かしようとすると問題になると思っています。 基底クラスのコンストラクタ内で派生クラスメンバの参照に対して何かしなければ、 参照は有効で、派生クラスのコンストラクタ実行後であれば 問題なく動くと思ってよいでしょうか。 struct A { int& m_ref; A(int& ref) : m_ref(ref) { } }; struct B : public A { int m_obj; B() : A(m_obj) { } };

  • Javaの多態性について質問です

    Java初心者です。どなたかお力をお貸しください。 ------------------- class Animal { public void eat() { // 汎用的なコード } } class Dog extends Animal { public void eat() { // 特化したコード } public void bite() { // Dog特有のコード } } ------------------- 上記のクラスについて質問があります。 Animal obj = new Dog(); obj.bite(); このコードがコンパイルエラーになるのは何故でしょうか? コンパイラが参照型のみをチェックし、Animalクラスにbiteメソッドが 無いため、エラーを出すと参考書に書いてありました。 つまり、スーパークラス型の参照変数にサブクラスのインスタンスを格納し、 サブクラス特有のメソッドをコールできないとはどういう意図なんでしょうか? コンパイラのチェックで引っかかるのは分かったのですが、 オブジェクト指向としては、この使い方は推奨されないということでしょうか? (Animalの参照で、Dog特有のメソッドは使わない?) 実際にJavaでプログラムを組むときには、こんな使い方をしないのですか? 有知識者の方、教えて下さい。 私は、オブジェクト指向の多態性の理解が甘いため、こんな質問をしているのだと 思います。申し訳ございません。

    • ベストアンサー
    • Java
  • Object指向で考えた場合、このケースはどうなる

    現在JavaでObject指向を取り入れたプログラミングをしているのですが、疑問が出てきたので質問させていただきます。 例をあげて説明させていただくと、 乗り物、車、ベンツ という3つのObjectがあります。 これらを abstract class 乗り物 abstract class 車 extends 乗りもの class ベンツ extends 車 と書いたのですが、乗り物class内で宣言したabstractメソッドが、ベンツで実装されていなくてもエラーが出ませんでした。 この事から、自分は何か設計を間違えているのではないかと疑問を持ちました。 自分の設計はあっているのでしょうか?ご回答よろしくお願いします。

    • ベストアンサー
    • Java

専門家に質問してみよう