web-dev-qa-db-ja.com

オーバーライドされたメソッドは戻り値の型が異なる場合がありますか?

オーバーライドされたメソッドに異なる戻り値のタイプを指定できますか

118
santidoo

Javaサポート* オーバーライドされたメソッドの共変戻り型。これは、オーバーライドされたメソッドにmore特定の戻り値の型があることを意味します。つまり、新しい戻り値の型がオーバーライドするメソッドの戻り値の型に割り当て可能である限り、許可されます。

例えば:

class ShapeBuilder {
    ...
    public Shape build() {
    ....
}

class CircleBuilder extends ShapeBuilder{
    ...
    @Override
    public Circle build() {
    ....
}

これは Java言語仕様のセクション8.4.5 で指定されています:

戻り値の型が参照型の場合、戻り値の型は互いにオーバーライドするメソッド間で異なる場合があります。 return-type-substitutabilityの概念は、共変の戻り値、つまり戻り値の型をサブタイプに特化することをサポートします。

戻りタイプR1のメソッド宣言d1は、次の条件が当てはまる場合にのみ、戻りタイプR2の別のメソッドd2に対してreturn-type-substitutableです。

  • R1が無効の場合、R2は無効です。

  • R1がプリミティブ型の場合、R2はR1と同一です。

  • R1が参照タイプの場合:

    • R1がR2のサブタイプであるか、R1が未チェックの変換(§5.1.9)によってR2のサブタイプに変換されるか、または

    • R1 = | R2 |

(「| R2 |」は、 §4.6のJLS で定義されているR2の消去を指します。)


* Java 5より前のJavaには、invariant戻り型があり、メソッドの戻り型を意味していましたオーバーライドされるメソッドと正確に一致するためにオーバーライドが必要です。

156

はい、異なる場合がありますが、いくつかの制限があります。

Java 5.0より前では、メソッドをオーバーライドする場合、パラメーターと戻り値の型の両方が正確に一致する必要があります。 Java 5.0では、共変戻り型と呼ばれる新しい機能が導入されています。同じシグネチャでメソッドをオーバーライドできますが、返されたオブジェクトのサブクラスを返します。言い換えると、サブクラスのメソッドは、スーパークラスの同じシグネチャを持つメソッドによって返される型のサブクラスである型のオブジェクトを返すことができます。

21
Pankaj Goyal

はい、サブタイプを返す場合。以下に例を示します。

package com.sandbox;

public class Sandbox {

    private static class Parent {
        public ParentReturnType run() {
            return new ParentReturnType();
        }
    }

    private static class ParentReturnType {

    }

    private static class Child extends Parent {
        @Override
        public ChildReturnType run() {
            return new ChildReturnType();
        }
    }

    private static class ChildReturnType extends ParentReturnType {
    }
}

このコードはコンパイルおよび実行されます。

18
Daniel Kaplan

大まかに言えば、オーバーライドメソッドの戻り値のタイプは異なる場合があります。しかし、それは簡単ではありませんが、これに関連するケースがいくつかあります。

ケース1:戻り値の型がプリミティブデータ型またはvoidの場合。

出力:戻り値の型がvoidまたはプリミティブの場合、親クラスメソッドとオーバーライドメソッドのデータ型は同じである必要があります。例えば戻り値の型がint、float、stringの場合、同じである

ケース2:戻り値の型が派生データ型の場合:

出力:親クラスメソッドの戻り値の型が派生型の場合、オーバーライドメソッドの戻り値の型は、派生データ型に対するサブクラスの派生データ型と同じです。例えばクラスA BがAのサブクラスCがBのサブクラスDがCのサブクラスであり、スーパークラスがタイプAを返す場合、オーバーライドメソッドがサブクラスである場合、サブクラスはA、B、CまたはDタイプ、つまりそのサブタイプを返すことができますこれは共分散とも呼ばれます。

7
Avinav Mishra

はい可能です。戻り値の型は、親クラスメソッドの戻り値の型が
子クラスメソッドのスーパータイプリターンタイプ..
手段

            class ParentClass {
                  public Circle() method1() {
                    return new Cirlce();
                  }
            }

            class ChildClass extends ParentClass {
                  public Square method1() {
                     return new Square();
               }
            }


            Class Cirlce {

            }

            class Square extends Circle {

            }

        ---

これが異なる場合、異なる戻り型を許可できます...

オーバーライドと戻り値の型、および共変の戻り値
サブクラスは、継承されたバージョンと正確に一致するメソッドを定義する必要があります。または、Java 5の時点で、戻り値の型を変更できます

サンプルコード


                                                                                                            class Alpha {
          Alpha doStuff(char c) {
                  return new Alpha();
              }
           }
             class Beta extends Alpha {
                    Beta doStuff(char c) { // legal override in Java 1.5
                    return new Beta();
                    }
             } } 
2
sandeep1987

戻り値の型は、スーパークラスの元のオーバーライドされたメソッドで宣言された戻り値の型と同じか、そのサブタイプでなければなりません。

2
sandeep1987

はい、可能です

class base {

 base show(){

System.out.println("base class");

return new base();

}
}

class sub extends base{

sub show(){

    System.out.println("sub class");

    return new sub();

 }
}

class inheritance{

 public static void main(String []args) {

        sub obj=new sub();

            obj.show();
 }
}
1
Rahul Bhadana

まあ、答えはイエスです...そしてノー。

質問次第です。ここの誰もがJava> = 5について回答し、Java <5は共変の戻り値型を特徴としていないと述べた人もいました。

実際、Java言語仕様> = 5ではサポートされていますが、Javaランタイムではサポートされていません。特に、JVMは共変の戻り値型をサポートするように更新されていません。

「賢い」動きと見られていたが、Javaの歴史上最悪の設計決定の1つになったJava 5は、JVMまたはクラスファイルの仕様をまったく変更せずに、多くの新しい言語機能を実装しました。代わりに、すべての機能はjavacのトリックで実装されました。コンパイラは、ネスト/内部クラスのプレーンクラス、ジェネリックの型消去とキャスト、ネスト/内部クラスのプライベート「フレンドシップ」の合成アクセサ、外部「this」の合成インスタンスフィールドを生成/使用しますポインター、「。class」リテラルなどの合成静的フィールドなど.

また、共変の戻り値の型は、javacによって追加された構文糖衣です。

たとえば、これをコンパイルする場合:

class Base {
  Object get() { return null; }
}

class Derived extends Base {
  @Override
  @SomeAnnotation
  Integer get() { return null; }
}

javacは、Derivedクラスの2つのgetメソッドを出力します。

Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }

生成されたブリッジメソッド(バイトコードでsyntheticおよびbridgeとマーク)は、実際にはObject:Base:get()をオーバーライドするものです。これは、JVMに対して、戻り値の異なるメソッドが完全に独立しており、互いにオーバーライドできないためです。期待される動作を提供するために、ブリッジは単に「実際の」メソッドを呼び出します。上記の例では、javacは@SomeAnnotationでDerivedのブリッジメソッドと実際のメソッドの両方に注釈を付けます。

Java <5でこのソリューションを手動でコーディングすることはできません。ブリッジメソッドと実際のメソッドは戻り値の型が異なるだけであり、Javaプログラム内で共存できないためです。しかし、JVMの世界では、メソッドの戻り値の型は(引数と同じように)メソッドシグネチャの一部であるため、同じ名前の同じ引数を取る2つのメソッドは、戻り値の型が異なるため、JVMによって完全に独立していると見なされます。共存できます。

(ところで、フィールドのタイプは同様にバイトコードのフィールド署名の一部であるため、異なるタイプの複数のフィールドを単一のバイトコードクラス内で同じ名前にすることは合法です。)

あなたの質問に完全に答えるために:JVMは共変の戻り値型をサポートしていませんが、javac> = 5はコンパイル時に甘い構文糖衣でそれを偽装します。

0
Lanchon

はい。オーバーライドされたメソッドは、異なる戻り値の型を持つことができます。

ただし、オーバーライドされたメソッドには、実際のメソッドの戻り値型のより具体的な戻り値型が必要であるという制限があります。

すべての答えは、実際のメソッドの戻り値型のサブクラスである戻り値型を持つためのオーバーライドされたメソッドの例を示しています。

例えば ​​:

public class Foo{

   //method which returns Foo
  Foo getFoo(){
      //your code         
  }

}

 public class subFoo extends Foo{

  //Overridden method which returns subclass of Foo
  @Override
  subFoo getFoo(){
      //your code         
  }

}

ただし、これはサブクラスに限定されるものではありません。インターフェイスを実装するクラスでさえ、インターフェイスの特定のタイプであるため、インターフェイスが期待される戻りタイプになる可能性があります。

例えば ​​:

public interface Foo{

   //method which returns Foo
  Foo getFoo();

}

 public class Fizz implements Foo{

  //Overridden method which returns Fizz(as it implements Foo)
  @Override
  Fizz getFoo(){
      //your code         
  }

}
0
Sachin Kumar

はい、できます!共変の戻り値の型は一般的な例の1つです

0
user11198642

他の答えはすべて正しいですが、驚くべきことに、ここでは理論的な側面を省略しています:戻り値の型は異なる場合がありますが、restrictLiskov Substitution Principle のためのスーパークラス。

とても簡単です:メソッドを呼び出す「クライアント」コードがある場合:

int foo = someBar.bar();

次に、上記が機能する必要があります(bar()のどの実装が呼び出されても、intであるものを返します)。

意味:bar()をオーバーライドするBarサブクラスがある場合、「呼び出し元コード」を壊さない何かを返す必要があります。

つまり、ベースbar()がintを返すことになっていると仮定します。次に、サブクラスはshortを返すことができますが、呼び出し元はlong値を処理できますが、shortは処理しないため、longは返しません。

0
GhostCat