수퍼 타입이 필요한 서브 클래스 객체를 인수로 전달하여 메소드 재정의


12

나는 단지 자바를 배우고 연습 프로그래머가 아닙니다.

내가 따르는 책은 메소드를 재정의 할 때 인수 유형이 같아야하지만 반환 유형은 다형성 호환 가능하다고 말합니다.

내 질문 은 재정의 메소드에 전달 된 인수가 예상되는 수퍼 유형의 하위 클래스 유형이 될 수없는 이유는 무엇입니까?

오버로드 된 메소드에서 객체에 대해 호출하는 모든 메소드는 객체에서 정의됩니다.


제안 된 중복에 대한 참고 사항 :

번째 제안 은 클래스 계층 구조와 기능을 넣을 위치에 관한 것으로 보입니다. 내 질문은 언어 제한이 존재하는 이유에 더 중점을 둡니다.

두 번째 제안은 내가 부탁 해요 무엇을 할 수 있지만 방법을 설명합니다 그런 식으로 일을 할 수는있다. 내 질문은 이유에 중점을 둡니다.


1
질문과 이전 질문에 대답 : "추가 된 제약 조건이 기본 수준의 작업은 항상 파생 클래스 ...에 적합하지 않은 수 있기 때문 일반적으로리스 코프 치환 원칙 (LSP)를 실패로 간주됩니다"
모기


@gnat 문제는 ​​인수에 대해 더 구체적인 하위 유형을 요구하는 것이 일부 컴퓨터 원칙을 위반하는지 여부가 아니라 문제가 가능한지 여부입니다.
user949300

답변:


18

처음에 질문에서 언급 한 개념을 공변량 반환 유형 이라고 합니다 .

공변 리턴 유형은 메소드가 특정 유형의 오브젝트를 리턴해야하고 대체 메소드를 대체하면 실제로 서브 클래스를 리턴 할 수 있기 때문에 작동합니다. 경우, 자바와 같은 언어의 하위 유형 규칙에 따라 S의 하위 유형이다 T어디든지 다음, T우리가 전달할 수 있습니다 나타납니다 S.

따라서 S예상되는 메서드를 재정 의 할 때 a 를 반환하는 것이 안전 합니다 T.

재정의 된 메서드가 재정의 된 메서드에서 요청한 인수의 하위 유형 인 인수를 사용한다는 점을 받아들이 겠다는 제안은 형식 시스템에서 소리가 나지 않기 때문에 훨씬 더 복잡합니다.

한편으로, 위에서 언급 한 것과 동일한 하위 유형 규칙에 따라 대부분의 경우 이미 원하는 작업에 적용됩니다. 예를 들어

interface Hunter {
   public void hunt(Animal animal);
}

이 클래스의 구현이 어떤 종류의 동물도받지 못하게 막는 것은 없습니다. 이미 질문의 기준을 충족하고 있기 때문입니다.

그러나 제안한대로이 방법을 무시할 수 있다고 가정 해 봅시다.

class MammutHunter implements Hunter {
  @Override
  public void hunt(Mammut animal) {
  }
}

다음은 재미있는 부분입니다. 이제 할 수 있습니다.

AnimalHunter hunter = new MammutHunter();
hunter.hunt(new Bear()); //Uh oh

공용 인터페이스에 따라 AnimalHunter모든 동물을 사냥 할 수 있어야하지만 구현에 따라 개체 MammutHunter만 허용해야 Mammut합니다. 따라서 재정의 된 메서드는 공용 인터페이스를 만족하지 않습니다. 우리는 방금 유형 시스템의 건전성을 깨뜨 렸습니다.

제네릭을 사용하여 원하는 것을 구현할 수 있습니다.

interface AnimalHunter<T extends Animal> {
   void hunt(T animal);
}

그런 다음 MammutHunter를 정의 할 수 있습니다.

class MammutHunter implements AnimalHunter<Mammut> {
   void hunt(Mammut m){
   }
}

그리고 일반 공분산과 반공 분산을 사용하면 필요할 때 유리하게 규칙을 완화 할 수 있습니다. 예를 들어 포유류 사냥꾼이 특정 상황에서만 고양이를 사냥 할 수 있도록 할 수 있습니다.

AnimalHunter<? super Feline> hunter = new MammalHunter();
hunter.hunt(new Lion());
hunter.hunt(new Puma());

MammalHunter구현을 가정 합니다 AnimalHunter<Mammal>.

이 경우에는 허용되지 않습니다.

hunter.hunt(new Mammut()):

mammuts가 포유류 인 경우에도 여기서 사용하는 반 변형 유형에 대한 제한으로 인해 허용되지 않습니다. 그래서, 당신은 여전히 ​​당신이 언급 한 것과 같은 것들을하기 위해 타입을 제어 할 수 있습니다.


3

문제는 인수로 제공된 객체를 사용하여 재정의하는 방법이 아닙니다. 문제는 메소드를 사용하는 코드가 메소드에 피드를 허용하는 인수 유형입니다.

재정의 방법은 재정의 방법의 계약을 이행해야합니다. 재정의 된 메서드가 일부 클래스의 인수를 허용하고 하위 클래스 만 허용하는 메서드로 재정의하면 계약을 이행하지 않습니다. 그것이 유효하지 않은 이유입니다.

보다 구체적인 인수 유형으로 메소드를 대체하는 것을 오버로드 라고 합니다. 이름은 같지만 더 구체적이거나 다른 유형의 인수로 메소드를 정의합니다. 원래 방법 외에 오버로드 된 방법을 사용할 수 있습니다. 호출되는 메소드는 컴파일시 알려진 유형에 따라 다릅니다. 메소드를 오버로드하려면 @Override 어노테이션을 삭제해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.