programing

재정의된 메서드는 반환 유형이 다를 수 있습니까?

prostudy 2022. 7. 29. 22:19
반응형

재정의된 메서드는 반환 유형이 다를 수 있습니까?

재정의된 메서드의 반환 유형은 다를 수 있습니까?

Java는* 재정의된 메서드에 대해 공변 반환 유형을 지원합니다.즉, 오버라이드된 메서드가 보다 구체적인 반환 유형을 가질 수 있습니다.즉, 재정의하는 메서드의 반환 유형에 새 반환 유형을 할당할 수 있는 경우 허용됩니다.

예를 들어 다음과 같습니다.

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

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

이는 Java Language Specification 섹션 8.4.5에 기재되어 있습니다.

반환 유형이 참조 유형인 경우 서로 재정의하는 메서드에 따라 반환 유형이 다를 수 있습니다.return-type-substitability의 개념은 공변량 반환, 즉 반환 유형을 하위 유형으로 특수화하는 것을 지원합니다.

반환 타입 R1의 메서드 선언 d1은 다음 조건이 충족되는 경우에만 반환 타입 R2의 다른 메서드 d2에 대해 반환 타입 치환 가능합니다.

  • R1이 무효일 경우 R2는 무효입니다.

  • R1이 원시형일 경우 R2는 R1과 동일합니다.

  • R1이 기준 유형인 경우:

    • R1은 R2의 서브타입이거나 체크되지 않은 변환( convers5.1.9)에 의해 R1을 R2의 서브타입으로 변환할 수 있다.

    • R1 = |R2|

("|R2|"는 JLS의 § 4.6에서 정의된 바와 같이 R2의 삭제를 의미합니다.)


* Java 5 이전 Java는 불변 반환 타입을 가지고 있었습니다.즉, 오버라이드되는 메서드와 정확히 일치시키기 위해 메서드 오버라이드의 반환 타입이 필요했습니다.

네, 다를 수 있지만 몇 가지 제한이 있습니다.

Java 5.0 이전 버전에서는 메서드를 덮어쓸 때 파라미터와 반환유형이 모두 정확하게 일치해야 합니다.Java 5.0은 공변 반환 유형이라는 새로운 기능을 도입했습니다.동일한 시그니처를 가진 메서드를 덮어쓰고 반환되는 객체의 서브클래스를 반환할 수 있습니다.

즉, 서브클래스 내의 메서드는 슈퍼클래스 내의 동일한 시그니처를 가진 메서드에 의해 반환되는 타입의 서브클래스인 오브젝트를 반환할 수 있다.

예, 서브타입이 반환되는 경우.다음은 예를 제시하겠습니다.

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

이 코드는 컴파일되어 실행됩니다.

대체적으로 말하면, 우선 방식의 yes 반환 유형은 다를 수 있습니다.하지만 이것과 관련된 몇 가지 사건들이 있기 때문에 그것은 간단하지 않다.

사례 1: 반환 유형이 원시 데이터 유형 또는 무효인 경우.

출력: 반환 유형이 void 또는 primitive인 경우 부모 클래스 메서드와 재정의 메서드의 데이터 유형이 같아야 합니다. 예를 들어 반환 유형이 int, float, string인 경우 같아야 합니다.

케이스 2: 반환 유형이 파생 데이터 유형인 경우:

출력: 부모 클래스 메서드의 반환 유형이 파생된 유형인 경우 덮어쓰기 메서드의 반환 유형은 파생된 데이터 유형과 동일한 파생된 데이터 유형입니다. 예를 들어 클래스 A가 있고 B가 A의 서브 클래스이고 C가 B의 서브 클래스이고 D가 C의 서브 클래스인 경우 슈퍼 클래스 A가 오버라이드됩니다.하위 클래스의 thod는 A 또는 B/C/D 유형, 즉 하위 유형을 반환할 수 있습니다.이를 공분산이라고도 합니다.

반환 부모 반환 유형반환되는 경우에만 .
상위 유형의 자식 클래스 메서드 반환 유형입니다.
「」를 의미합니다.

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

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

Class Circle {

}

class Square extends Circle {

}


If this is the then different return type can be allowed...

다른 답변은 모두 맞지만 놀랍게도 이론적인 측면은 모두 빠져 있습니다.반환 유형은 다를 수 있지만 리스코프 대체 원칙 때문에 슈퍼 클래스에서 사용되는 유형만 제한할 수 있습니다.

매우 간단합니다. "클라이언트" 코드가 있으면 메서드를 호출할 수 있습니다.

int foo = someBar.bar();

통해야 해야 한다).int어떤 bar()호출됩니다).

""을 덮어쓰는 : " " " " " " " "bar()그래도 '코드'가 깨지지 않는 건 반납해야 돼요

가 「」, 「」라고 합니다.bar()하다 하위 가 반환될 수 .short. -근데 안 돼요.long는, 「이렇게 하면 때문에」를할 수 있기 때문입니다.short '는 제외)long!

답은 '그렇다'입니다그리고 아니다.

질문에 따라 다르죠여기 계신 모든 분들이 Java > = 5에 대해 답변하셨고, 일부는 Java < 5가 공변 반환 유형을 지원하지 않는다고 언급하셨습니다.

실제로 Java 언어 사양 > = 5는 이를 지원하지만 Java 런타임은 지원하지 않습니다. 특히 JVM은 공변 반환 유형을 지원하도록 업데이트되지 않았습니다.

당시에는 "깨끗한" 움직임으로 보였지만 결국 Java 역사상 최악의 설계 결정 중 하나가 되었습니다. 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 클래스에서 다음 두 가지 get 메서드를 출력합니다.

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

생성된 브리지 방식(마킹 완료)synthetic그리고.bridge바이트 코드)는, 실제로는, 이 값을 무효로 합니다.Object:Base:get()JVM에 대해 다른 리턴 타입을 가진 메서드는 완전히 독립적이며 서로 덮어쓸 수 없기 때문에 예상되는 동작을 제공하기 위해 브리지에서는 단순히 "실제" 메서드를 호출합니다.위의 예에서 javac은 Derived with @SomeAnnotation의 브리지 메서드와 실제 메서드 모두에 주석을 붙입니다.

Java < 5에서는 이 솔루션을 수동으로 코드화할 수 없습니다.브릿지와 실제 메서드는 반환 타입이 다르기 때문에 Java 프로그램에서는 공존할 수 없기 때문입니다.그러나 JVM 세계에서는 메서드 리턴 타입은 메서드시그니처의 일부이기 때문에 (그들의 인수와 마찬가지로) 이름이 같고 동일한 인수를 사용하는 두 가지 메서드는 반환 타입이 다르기 때문에 JVM에 의해 완전히 독립된 것으로 간주되며 공존할 수 있습니다.

(BTW, 필드의 유형은 마찬가지로 바이트 코드의 필드 시그니처의 일부이기 때문에 다른 유형의 필드를 여러 개 가질 수 있지만 단일 바이트 코드클래스 내에 같은 이름을 붙이는 것은 합법입니다).

JVM은 공변량 리턴 타입을 지원하지 않지만 javac > = 5는 컴파일 시 달콤한 통사설탕 코팅으로 가짜로 만듭니다.

반환 유형은 슈퍼클래스의 원래 오버라이드 메서드에서 선언된 반환 유형과 같거나 하위 유형이어야 합니다.

재정의 및 반환 유형 및 공변 반환
하위 클래스는 상속된 버전과 정확히 일치하는 메서드를 정의해야 합니다.또는 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();
                    }
             } } 
As of Java 5, this code will compile. If you were to attempt to compile this code with a 1.4 compiler will say attempting to use incompatible return type – sandeep1987 1 min ago

네, 가능합니다.

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

예. 재정의된 메서드의 반환 유형이 다를 수 있습니다.

단, 오버라이드된 메서드는 실제 메서드의 반환 유형보다 구체적인 반환 유형을 가져야 한다는 제한이 있습니다.

모든 답변은 실제 메서드의 반환 유형의 하위 클래스인 반환 유형을 가지기 위해 재정의된 메서드의 예를 제시했습니다.

예를 들어 다음과 같습니다.

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         
  }

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

언급URL : https://stackoverflow.com/questions/14694852/can-overridden-methods-differ-in-return-type

반응형