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


134

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


2
同じまたはより狭い戻り値の型がない場合は、次の結果が得られます::error: method() in subclass cannot override method() in superclass
Quazi Irfan、2015

回答:


176

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

例えば:

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

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

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

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

戻り型R1のメソッド宣言d1は、戻り型R2の別のメソッドd2の戻り型置換可能です。ただし、次の条件が当てはまる場合に限ります。

  • R1が無効の場合、R2も無効になります。

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

  • R1が参照型の場合:

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

    • R1 = | R2 |

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


* Java 5より前は、Javaには不変の戻り型がありました。つまり、オーバーライドされるメソッドと正確に一致するために必要なメソッドオーバーライドの戻り型がありました。


26

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

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


20

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

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 {
    }
}

このコードはコンパイルして実行されます。


9

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

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

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

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

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


あなたのこのコメントは、私はクラスABはACへのサブクラスである必要があり曖昧であるBDへのサブクラスである、それはクラスABはACまたはAのサブクラスである何を意味するのか、Bはその混乱、C手段Aのサブクラスである
ディネッシュkandpal

5

はい、親クラスのメソッドの戻り値の型がある場合にのみ..戻り型が異なることが可能です
。..子クラスのメソッドの戻り値の型のスーパータイプは、
手段

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

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

Class Circle {

}

class Square extends Circle {

}


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


2

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

質問によって異なります。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(); }

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

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

(ところで、フィールドのタイプはバイトコードのフィールドシグネチャの一部であるので、単一のバイトコードクラス内で異なるタイプの複数のフィールドに同じ名前を付けることは合法です。)

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


1

オーバーライド型と戻り型、および共変戻り値
サブクラスは、継承されたバージョンと正確に一致するメソッドを定義する必要があります。または、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();
                    }
             } } 
Java 5、このコードはコンパイルされます。このコードを1.4コンパイラでコンパイルしようとすると、互換性のない戻り値の型を使用しようとすると表示されます– sandeep1987 1分前


1

他の答えはすべて正解ですが、驚くべきことに、ここでは理論的な側面をすべて省略しています。戻り値の型は異なる場合がありますが、スーパークラスで使用される型を制限できるのは、リスコフの置換原理のためです。

それは非常に単純です:いくつかのメソッドを呼び出す「クライアント」コードがある場合:

int foo = someBar.bar();

次に、上記は機能する必要intbar()あります(呼び出される実装に関係なく何かを返す必要があります)。

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

つまり、ベースbar()がintを返すことになっていると仮定します。次に、サブクラスが戻る可能性shortがありますがlong、呼び出し元はshort値を正しく処理しますが、long


0

戻りの型は、スーパークラスの元のオーバーライドされたメソッドで宣言された戻りの型と同じか、そのサブタイプである必要があります。


5
2つの答えを組み合わせる必要があります。
theblang 2013

0

はい、可能です

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();
 }
}

0

はい。オーバーライドされたメソッドが異なる戻り値の型を持つ可能性があります。

しかし、制限は、オーバーライドされたメソッドが、実際のメソッドの戻り型のより具体的な型である戻り型を持つ必要があることです。

すべての回答には、オーバーライドされたメソッドの例があり、実際のメソッドの戻り型のサブクラスである戻り型を持っています。

例えば ​​:

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
class Phone {
    public Phone getMsg() {
        System.out.println("phone...");
        return new Phone();
    }
}

class Samsung extends Phone{
    @Override
    public Samsung getMsg() {
        System.out.println("samsung...");
        return new Samsung();
    }
    
    public static void main(String[] args) {
        Phone p=new Samsung();
        p.getMsg();
    }
}

これはどのように質問に答えますか?
ブランドなしのマンチェスター

これは、異なる戻り値型の例です。
パート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.