Java参照型の型変換について

このQ&Aのポイント
  • Javaにおける参照型の型変換について解説します。
  • 参照型の型変換には暗黙の型変換とキャストがあります。
  • スーパークラス型からサブクラス型への型変換やサブクラス型からスーパークラス型への暗黙の型変換が可能ですが、オブジェクトの性質は変化しません。
回答を見る
  • ベストアンサー

Java 「参照型の型変換」について

Java初心者です。 入門書を読んでいたら、「参照型の型変換」を説明している項目に 以下の方法で行うと書いてありました。 ==前提=== Personは親クラス Employeeは小クラス Engineerは孫クラス ======== (1)Engineer型からPerson型へ暗黙の型変換する場合 Person per1 = new Engineer(); (2)Person型からEngineer型へキャストする場合 Engineer eng1 = (Engineer) per1; (3)Person型からEmployee型へキャストする場合 Employee emp1 = (Employee) per1; ======== これ、変換の方法は上記で分かったのですが、 そもそも、 "何のために参照型の型変換を行うのか" "型変換を行うと、それぞれのオブジェクトの機能がどのように変わるのか" そういった説明が一切書いておらず、その意味するところが理解出来ませんでした。 スーパークラス型からサブクラス型にキャストする場合、 サブクラス型からスーパークラス型に暗黙の型変換する場合、 それぞれのオブジェクトの性質がどう変化するのでしょうか? メソッドやフィールドに対しての挙動が何か変わるのでしょうか? 基本データ型の型変換は分かり易いんですけどね。。 参照型はどうにも。。 教えて下さい!

  • Java
  • 回答数4
  • ありがとう数0

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

  • ベストアンサー
  • NNori
  • ベストアンサー率22% (377/1669)
回答No.1

これは、親、子、孫、のように一直線のクラスだけを考えるとあまりありがたみがありません。親から2種類以上の子がでてくるとありがたみがでます。 例えばPersonを親として、Employee、Studentという子クラスがあったとします。 で、EmployeeもStudentも同じように変数で捕まえておきたい場合にPersonを使うことができるのです。 Person papa = new Employee(); Person boku = new Student(); papa や boku は 同じ型(Person)なので、Personのメソッドが使えます。さらにvirtual なメソッドを定義しておけば、同じように扱うことができます。 例えば、Employee型には、CompanyName というメソッドがあり Student 型には SchoolName というメソッドがあったとしても、同じPerson型で受けることができるわけです。そしてPersonにBelongNameというvirtualなメソッドを用意しておいて、Employee のときは CompanyName を StudentのときはSchoolName を返すようにしておけば、Person 型の papa や boku から同じ名前のBelongNameというメソッドでそれぞれ最適なメソッドを呼び出すことができます。 こうすることで、すっきりわかりやすいプログラミングができるのです。上記の例は単純ですが、私はこの機能こそがクラスの継承の醍醐味だと考えています。

hakase-chan
質問者

補足

早速のご回答ありがとうございます! すみません、「virtualなメソッド」とはどういったものの事を言うのでしょうか? 参考書にも載っておらず。。。 その後の説明頂いた部分が理解出来ませんでした。。。 また、 >papa や boku は 同じ型(Person)なので、Personのメソッドが使えます。 これについては、 EmployeeもStudentもPersonを継承していた場合、 Employee papa = new Employee(); Student boku = new Student(); という書き方でも、 親に当たるPersonのメソッドは全く同じように利用可能ですよね?? 質問ばかりで申し訳ないです。

その他の回答 (3)

  • NNori
  • ベストアンサー率22% (377/1669)
回答No.4

#1です。 すみません、「virtualなメソッド」とはどういったものの事を言うのでしょうか? 参考書にも載っておらず。。。 その後の説明頂いた部分が理解出来ませんでした。。。 >>この回答は、#2さんのとおりです。 また、 >papa や boku は 同じ型(Person)なので、Personのメソッドが使えます。 これについては、 EmployeeもStudentもPersonを継承していた場合、 Employee papa = new Employee(); Student boku = new Student(); という書き方でも、 親に当たるPersonのメソッドは全く同じように利用可能ですよね?? >この場では、確かにpapa の宣言をEmployee型にしてもStudent型にしても大差ないです。 これら、papaとbokuを#3さんがおっしゃっているようにリストとか配列にいれたいとき何型で宣言しますか? こういう場合に継承が有効になるのです。つまり、共通するPerson型の配列を作っておけばEmployee型もStudent型も入れることができるのです。これが継承の利点です。 質問ばかりで申し訳ないです。

回答No.3

例えば Employee が給与計算用メソッド calcSalary を持っていたとします。 孫に Engineer と Managerが有るとすると、おそらく給与計算方法はかなり異なるでしょう。 しかし、calcSalaryのインターフェースは工夫すれば全く同じにできるでしょう。 このように、内容は異なるが意味的には同じ処理を見つけてインターフェースを合わせてゆく 設計作業を共通性ー可変性分析と言います。このような設計がなされていると、 後で、Employee の孫に Secretary が加わって、給与計算方法が違っても、 共通のインターフェースを使って実装すれば、既存のコードにほとんど 影響を与えません。細かな処理の違いは孫クラスの個々の処理が受け持ち、 上位の処理は Employee の メソッドで処理を進めることができます。 これをもし、変数の型を Engineer とか Secretary とか書いてしまったら広範囲に 改造が及ぶことになるでしょう。上位の処理内容が全く同じでも、別々にコードを 書く破目になります。 ダウンキャストですが、これは上位のインターフェースではなくて、クラスのより具体的な メソッドに上位からアクセスしなければならないときに使います。 これは使わざる得ない時もあるのですが、悪い兆候でもあります。出来るだけ使わないように 工夫するのが無難です。

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

あんまりいい例じゃないけど: Employeeクラスのオブジェクトを引数に持つメソッド aMethod(Employee employee) には Employeeクラスのオブジェクトでも Engineerクラスのオブジェクトでも渡すことができます. そして, このメソッドの内部ではどちらのオブジェクトであっても Employeeクラスのオブジェクトとして扱われ, Employeeクラスのインスタンスメソッド (とそのスーパークラスである Personクラスのインスタンスメソッド) を呼び出すことはできますが, Engineerクラスのインスタンスメソッドは (たとえ実際に渡したのが Engineerクラスのオブジェクトであったとしても) 呼び出すことはできません. #1 の virtual は, ここで「Employeeクラスのインスタンスメソッドを呼び出すときに, 実際に呼び出されるメソッドがどれか」を指定する用語です. 「常に Employeeクラスのインスタンスメソッドが呼び出される」なら nonvirtual, 「実際のオブジェクトのクラスに従って (つまりもともと Employeeクラスのオブジェクトなら Employeeクラスの, もとが Engineerクラスのオブジェクトなら Engineerクラスの) インスタンスメソッドが呼び出される」なら virtual です... が, Java のメソッドは全部 virtual なのでここはあんまり気にしなくていいです. この辺は「単独のデータとして持つ」ときには無視していいんですが, 「複数のデータがあってそれらを一括して管理する」ときには重要です. 例えば「全従業員のリスト」を考えると List<Employee> を使うことになり, このリストには Employeeクラスのオブジェクトと Engineerクラスのオブジェクトを混在することができます (そしてそれらは全て「Employeeクラスのオブジェクト」として扱われる).

関連するQ&A

  • javaの「型」がよくわかりません。

    java初心者です。 本日、参考書を読んでいるとき、次のような式および文がありました。なお、以下はスーパークラスにpersonクラスがあり、studentクラスとteacherクラスが継承しています。personクラスがworkメソッドを持ってます。 //通常の3倍働いてもらう void work(Person p){ p.work(); p.work(); p.work(); } 「引数をperson型にしているので、このworkメソッドにはstudentクラスとteacherクラスのインスタンスも渡すことができます。」 私の中で、型はあくまで指示的なもの、および宣言に利用するものだと思ってました。基本型なら「この形のものを作るよ」とか、voidなら「戻り値はないんだよ」とか。 結局「型」とは何なんでしょうか? 初心者にもわかるよう、教えていただけないでしょうか?よろしくお願いします。

    • ベストアンサー
    • Java
  • C#で型変換がうまくいきません。

    C#で型変換がうまくいきません。 short r; byte[] b = new byte[] {1,2,3}; r = (short)b[1] * (short)256; というコードを書くと、 型 'int' を 'short' に暗黙的に変換できません。明示的な変換が存在します。(cast が不足していないかどうかを確認してください) と出てしまいます。キャストしているのに何がいけないのか全くわかりません。 どうぞ宜しくお願いいたします。

  • サブクラス型オブジェクトをスーパークラス方に代入

    ある所で下記のような継承についての記述をみつけました。 ----------------------------------------------------------------------------- 継承の目的は、あるクラスで実装したメソッドなどの機能を利用して、 さらに実装を追加する差分コーディングです。 一つのクラスから複数のサブクラスを作ることも良くあります。 このような時、それらのサブクラス型オブジェクトの参照を代入できる変数として、 スーパークラス型変数を使うことがしばしばあります。 ----------------------------------------------------------------------------- サブクラス型オブジェクトの参照を代入できる変数として、 スーパークラス型変数を使うことがある、と いうのはどういった場合に使うのでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Java
  • 暗黙の型変換をやめたい

    ASP.NET(C#2.0)からSQLServer2008R2のストアドプロシージャをコールする際、暗黙の型変換を使うとパフォーマンスが落ちるらしいので、全て明示的な型変換に修正したいと思っています。 MySQLをselectした値をリーダー(reader)に格納し、SQLServerにストアドコール時にパラメータ指定してinsertするのですが、何が暗黙的で何が明示的なのかわかりません。 下記は引数1にパラメータ、引数2にDBType(省略可)、引数3に値を指定しています。 [暗黙的かと思われるパラメータの渡し方] AddParameter("@パラメータ1", reader["値1"]); //char(2) AddParameter("@パラメータ2", DbType.string, reader["値2"].ToString()); //nvarchar(20) [明示的かと思われるパラメータの渡し方] AddParameter("@パラメータ3", DbType.DateTime, Convert.ToDateTime(reader["値3"])); //datetime AddParameter("@パラメータ4", DbType.Currency, (Convert.ToDecimal(reader["値4"])) * 100); //money 暗黙の型変換とは、引数3の型を指定しない場合に起こるという認識で合っていますでしょうか?

  • 下記の様に、Employeeの(クラス)型でキャストした場合の、Emp

    下記の様に、Employeeの(クラス)型でキャストした場合の、EmployeeのVectorを使った書き方がよく分かりません。Employeeは複数の従業員の名前をVector形式で表現したものになります。Employeeクラスの中で、Vector型のEmployeeや関数print()をどうやって書いたらいいのか分かりかねています。御教示願えたらと思っています。 //ここから public class Main { /** * @param args */ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ Traversable employees; employees = new TraversableVector(); // ... java.util.Enumeration e = employees.createEnumeration(); while(e.hasMoreElements()) { Employee emp = (Employee)e.nextElement(); emp.print(); } } } //ここまで よろしくお願い致します。

    • ベストアンサー
    • Java
  • 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
  • C#で実行時にメソッドの返り値の型を変化させる

    C# で、実行時にメソッドの返り値の型を変化させることは可能でしょうか? たとえば、 public class MyData { object o; public void setValue( object a ) { o = a; } public object getValue() { return o; } } というクラスがあるとき、 static void Main(string[] args) { MyData a = new MyData(); a.setValue( 3 ); Console.WriteLine( a.getValue().GetType().ToString() ); int i = (int)a.getValue(); } というコードを実行すると、 System.Int32 と表示されます。Main の 4 行目で、(int)のキャストをはずすと、object から int への暗黙の変換はできませんというコンパイルエラーになります。 この(int)のキャストをしなくてもエラーにならないような getValue の関数はできないでしょうか? o は、数値型であるとします。 たとえば、MyData に、 public int getInt() { return (int)o; } とすれば、必ず int を返すようなメソッドはできると思うのですが、これだと、getByte() や、getDouble() などのように、考えられるすべての型を想定してメソッドを作ることになってしまいます。 そうではなく、getValue() で、少なくとも数値型の暗黙の変換はしてくれるようなことにできないでしょうか。 よろしくお願いします。

  • 継承における暗黙のデフォルトコンストラクター

    ”継承の際、スーパークラスで引数なしのコンストラクターが省略せずにきちんと記述されるなら、そのサブクラスでコンストラクターを記述しなくても、スーパークラスの引数なしのコンストラクターが受け継がれるためコンパイルエラーがおきない。”のは分かりますが”スーパークラスで引数なしのコンストラクターが省略され、かつサブクラスでコンストラクターを省略した場合”はなぜコンパイルエラーがおきるのでしょうか? 暗黙の内にスーパークラスにコンストラクターが生成され、それがサブクラスに受け継がれることは出来ないのでしょうか? 宜しく願います。

  • javaで、オブジェクトを生成しないとメソッドは使えないんですか?

    javaで、オブジェクトを生成しないとメソッドは使えないんですか? そのように習ったのですが、サブクラスのメソッド定義の中で、オブジェクトを生成せずにスーパークラスのメソッドを使える例(下に簡単に書きました)をみて、分からなくなってしまいました。 おしえてください、よろしくおねがいします。 ------------------------------- class superclass { method_a(){ ~~~~ } } --------------------------- class subclass { method_b(){ super.method_a(); }

    • ベストアンサー
    • Java
  • void*型の配列について

    void* a[2]; void* b = a; void* c[2] = (void *[2])b; error C2440: '型キャスト' : 'void *' から 'void *[2]' に変換できません。 配列型への変換はありませんが、参照またはポインタから配列への変換があります。 void*型にした a を再度void*型の配列に戻すにはどのように記述すればよいでしょうか? 環境はXP(SP3)のVS2008 MFC です。 宜しくお願いいたします。

専門家に質問してみよう