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에 '. 귀하의 예에서 이는 다음과 일치합니다. BC 와 같지만 추가 기능이 있습니다. 기능은 실현이 아니라 여기에 관련됩니다.


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.