Java generics-왜 "extends T"가 허용되지만 "implementation T"는 허용되지 않습니까?


306

Java 에서 유형 매개 변수의 경계를 정의 extends하기 위해 항상 " "대신 " " 를 사용하는 특별한 이유가 있는지 궁금합니다 implements.

예:

public interface C {}
public class A<B implements C>{} 

금지되어 있지만

public class A<B extends C>{} 

맞다. 그 이유는 무엇입니까?


14
사람들이 왜 Tetsujin no Oni의 답변이 실제로 질문에 대답한다고 생각하는지 모르겠습니다. 기본적으로 학술 문구를 사용하여 OP의 관찰 내용을 다시 말하지만 추론은하지 않습니다. "왜 없어요 implements?" - ""만 있기 때문입니다 extends.
— ThomasR

1
ThomasR : 그것은 "허용"에 대한 질문이 아니기 때문에 의미입니다. 제약 조건이 인터페이스인지 조상 타입인지에 상관없이 제약 조건을 가진 일반 소비 형을 작성하는 방법에는 차이가 없습니다.
— Tetsujin no Oni

새로운 것을 가져 오지 않고 더 복잡하게 만드는 이유에 대한 답변 ( stackoverflow.com/a/56304595/4922375 )을 implements추가했습니다. 도움이 되길 바랍니다.
— Andrew Tobilko

답변:


328

클래스 '구현'또는 '확장'사이에는 일반 제약 조건 언어에서 의미 상 차이가 없습니다. 제한 가능성은 'extends'와 'super'입니다. 즉,이 클래스는 다른 클래스 (extends)에 할당 가능하게 작동하거나이 클래스가 해당 클래스 (super)에서 지정할 수 있습니다.


@KomodoDave (답변 옆의 숫자가 올바른 것으로 표시됩니다. 다른 표시 방법이 있는지 확실하지 않습니다. 때로는 다른 답변에 추가 정보가 포함될 수 있습니다. 예를 들어 해결할 수없는 특정 문제가있었습니다. @Tetsujin no Oni (일부 코드를 사용하여 명확히 할 수 있습니까? thanx :))
— ntg

@ntg, 이것은 예제를 찾는 질문에 대한 아주 좋은 예입니다.이 시점에서 답변에 포함시키는 대신 주석으로 연결하겠습니다. stackoverflow.com/a/6828257/93922
— Tetsujin no Oni

1
나는 그 이유가 적어도 기본 클래스를 axtends하고 인터페이스를 확장하는 인터페이스뿐만 아니라 인터페이스를 나타내는 모든 클래스를 허용 할 수있는 생성자와 메소드를 가질 수있는 제네릭을 원한다고 생각합니다. 그런 다음 인터페이스의 존재 여부에 대한 Genric 테스트를 인스턴스화하고 실제 클래스를 유형 매개 변수로 지정하십시오. 이상적으로 class Generic<RenderableT extends Renderable implements Draggable, Droppable, ...> { Generic(RenderableT toDrag) { x = (Draggable)toDrag; } }One은 컴파일 타임 검사를 원합니다.
— peterk

1
@ peterk 그리고 RenderableT를 사용하면 Renderable, Draggable, Droppable ...을 확장 할 수 있습니다. 지우지 않는 제네릭이 당신에게 제공하지 않는 것을 이해하지 못한다면.
— Tetsujin no Oni

@TetsujinnoOni 당신이 원하지 않는 것은 특정 인터페이스 세트를 구현하는 클래스 만 허용하고 컴파일 된 OBJECT 클래스 (그 인터페이스를 나타내는)를 참조 할 수있는 컴파일 타임을 시행하는 것입니다. 적어도 컴파일 타임에 (그리고 바람직하게는 런타임에) 제네릭에 할당 된 모든 것을 지정된 인터페이스로 안전하게 캐스팅 할 수 있습니다. 자바가 지금 구현되는 방식은 아닙니다. 그러나 그것은 좋을 것입니다 :)
— peterk

77

대답은 다음과 같습니다  .

경계 형식 매개 변수를 선언하려면 형식 매개 변수 이름, extends키워드, 상한 […]을 차례로 나열하십시오 . 이 문맥에서 extends는 일반적인 의미로 extends(클래스에서와 같이) 또는 implements(인터페이스에서와 같이 ) 의미로 사용됩니다 .

그래서 당신은 그것을 가지고 있고, 약간 혼란스럽고 오라클은 그것을 알고 있습니다.


1
혼란을 더하기 위해서는 getFoo(List<? super Foo> fooList) 문자 그대로 Foo와 같이 확장 된 클래스에서만 작동합니다 class Foo extends WildcardClass. 이 경우 a List<WildcardClass>는 허용 가능한 입력입니다. 그러나 Foo구현 하는 클래스가 작동 class Foo implements NonWorkingWildcardClass하지 않는다고해서 해당 클래스가 List<NonWorkingWildcardClass>유효 하지는 않습니다 getFoo(List<? super Foo> fooList). 맑은!
— Ray

19

아마도 양쪽 (B와 C)의 경우 구현이 아닌 유형 만 관련이 있기 때문입니다. 당신의 예에서

public class A<B extends C>{}

B도 인터페이스가 될 수 있습니다. "extends"는 하위 인터페이스뿐만 아니라 하위 인터페이스를 정의하는 데 사용됩니다.

interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}

나는 보통 '으로'하위 슈퍼를 확장 '생각 서브가 같다 슈퍼 하지만, 추가 기능과 함께'및 'CLZ 구현 Intf에' '로 CLZ이 의 실현 Intf에 '. 귀하의 예에서 이는 다음과 일치합니다. B 는 C 와 같지만 추가 기능이 있습니다. 기능은 실현이 아니라 여기에 관련됩니다.


10
<B 확장 D & E>를 고려하십시오. E는 수업이 아니어야합니다.
— Tom Hawtin-tackline

7

기본 유형은 일반 매개 변수 일 수 있으므로 실제 유형은 클래스의 인터페이스 일 수 있습니다. 치다:

class MyGen<T, U extends T> {

또한 클라이언트 코드 관점에서 인터페이스는 클래스와 거의 구별 할 수 없지만 하위 유형의 경우 인터페이스가 중요합니다.


7

다음은 확장이 허용되는 위치와 원하는 항목에 대한보다 관련된 예입니다.

public class A<T1 extends Comparable<T1>>


5

사용하는 용어 중 임의의 종류입니다. 어느 쪽이든 될 수 있습니다. 아마도 언어 설계자들은 "확장자"를 가장 기본적인 용어로, "구현물"을 인터페이스의 특별한 경우라고 생각했을 것입니다.

그러나 나는 implements조금 더 의미가 있다고 생각 합니다. 나는 통신하는 더 많은 매개 변수 유형은 상속 관계에 있어야 할 필요가 없습니다, 그들이 될 수 있다고 생각 어떤 서브 타입 관계의 종류.

Java 용어집도 비슷한 견해를 나타 냅니다.


3

우리는 익숙해

class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}

이 규칙에서 약간 벗어난 것은 우리를 크게 혼란스럽게합니다.

유형 경계의 구문은 다음과 같이 정의됩니다.

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

( JLS 12> 4.4. 타입 변수>TypeBound )

변경해야한다면 반드시 implements사례를 추가해야합니다

TypeBound:
    extends TypeVariable 
    extends ClassType {AdditionalBound}
    implements InterfaceType {AdditionalBound}

두 개의 동일하게 처리 된 조항으로 끝납니다

ClassOrInterfaceType:
    ClassType 
    InterfaceType

( JLS 12> 4.3. 참조 유형 및 값>ClassOrInterfaceType )

우리가 돌봐 줄 필요가 있다는 점만 빼면 implements더 복잡해집니다.

나는 그것이 주된 이유하다고 생각 extends ClassOrInterfaceType대신에 사용 extends ClassType하고 implements InterfaceType복잡한 개념 내에서 일을 간단하게 유지하기 위해 -. 문제는 우리 모두를 커버 할 수있는 권리 단어가없는 것입니다 extends그리고 implements우리는 확실히 하나를 소개하고 싶지 않아요.

<T is ClassTypeA>
<T is InterfaceTypeA>

하지만 extends이 인터페이스와 함께 갈 때 약간의 혼란을 제공합니다, 그것은 광범위한 용어입니다 두 가지 경우를 설명하는 데 사용 할 수 있습니다. 유형 을 확장하는 개념 ( 인터페이스를 구현 하지 않고 클래스를 확장 하지 않음) 에 맞춰 마음을 조정하십시오 . 다른 유형 으로 유형 매개 변수를 제한하면 해당 유형이 실제로 무엇인지는 중요하지 않습니다. 상한 과 수퍼 타입 이라는 것만 중요합니다 .


-1

실제로 인터페이스에서 generic을 사용하면 키워드도 확장됩니다 . 코드 예제는 다음과 같습니다.

인사말 인터페이스를 구현하는 두 가지 클래스가 있습니다.

interface Greeting {
    void sayHello();
}

class Dog implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Dog: Hello ");
    }
}

class Cat implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Cat: Hello ");
    }
}

그리고 테스트 코드 :

@Test
public void testGeneric() {
    Collection<? extends Greeting> animals;

    List<Dog> dogs = Arrays.asList(new Dog(), new Dog(), new Dog());
    List<Cat> cats = Arrays.asList(new Cat(), new Cat(), new Cat());

    animals = dogs;
    for(Greeting g: animals) g.sayHello();

    animals = cats;
    for(Greeting g: animals) g.sayHello();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.