문제

나는 Java Generics를 잘 이해했다고 생각했지만 java.lang.enum에서 다음을 발견했습니다.

class Enum<E extends Enum<E>>

누군가이 유형 매개 변수를 해석하는 방법을 설명 할 수 있습니까? 유사한 유형 매개 변수를 사용할 수있는 다른 예제를 제공하기위한 보너스 포인트.

도움이 되었습니까?

해결책

이는 열거에 대한 유형 인수가 동일한 유형 인수를 갖는 열거에서 파생되어야 함을 의미합니다. 어떻게 이런 일이 일어날 수 있습니까? 유형 인수를 새로운 유형 자체로 만들어 따라서 상태 코드라는 열거가 있다면 다음과 같습니다.

public class StatusCode extends Enum<StatusCode>

이제 제약 조건을 확인하면 있습니다 Enum<StatusCode> - 그래서 E=StatusCode. 확인합시다 : E 연장하다 Enum<StatusCode>? 예! 우리는 괜찮아.

당신은 이것의 요점이 무엇인지 스스로에게 물어볼 것입니다 :) 글쎄, 그것은 열거의 API가 그 자체를 언급 할 수 있음을 의미합니다. Enum<E> 구현 Comparable<E>. 기본 클래스는 (열거의 경우) 비교를 수행 할 수 있지만 올바른 종류의 열거를 서로 비교할 수 있습니다. (편집 : 글쎄, 거의 - 하단의 편집을 참조하십시오.)

프로토콜 버퍼의 C# 포트에서 비슷한 것을 사용했습니다. "메시지"(불변) 및 "Builders"(Mexable, 메시지를 작성하는 데 사용됨)가 있으며 유형의 쌍으로 제공됩니다. 관련된 인터페이스는 다음과 같습니다.

public interface IBuilder<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

public interface IMessage<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

즉, 메시지에서 적절한 빌더 (예 : 메시지 사본을 가져 와서 비트를 변경할 수 있음)를 얻을 수 있으며 빌더에서 제작을 마치면 적절한 메시지를받을 수 있습니다. API의 좋은 직업 사용자는 실제로 이것에 관심을 갖지 않아도됩니다. 끔찍하게 복잡하며 몇 가지 반복을 가져 가서 어디에 있는지가 있습니다.

편집 : 이것은 괜찮은 유형 인수를 사용하는 홀수 유형을 만드는 것을 막지 않지만 같은 유형이 아닙니다. 목적은 오른쪽 당신을 보호하기보다는 사례입니다 잘못된 사례.

그래서 만약 Enum 어쨌든 Java에서 "특별히"처리되지 않았으므로 다음 유형을 만들 수 있습니다.

public class First extends Enum<First> {}
public class Second extends Enum<First> {}

Second 구현할 것입니다 Comparable<First> 보다는 Comparable<Second>... 하지만 First 그 자체는 괜찮을 것입니다.

다른 팁

다음은 책의 설명의 수정 된 버전입니다. 자바 제네릭 및 컬렉션: 우리는 있습니다 Enum 선언

enum Season { WINTER, SPRING, SUMMER, FALL }

클래스로 확장됩니다

final class Season extends ...

어디 ... 열거에 대한 어쨌든 모색화 된 기본 클래스가되어야합니다. 그것이 무엇인지 알아 봅시다. 글쎄, 요구 사항 중 하나입니다 Season 그것이 구현되어야한다는 것입니다 Comparable<Season>. 그래서 우리는 필요할 것입니다

Season extends ... implements Comparable<Season>

무엇을 사용할 수 있습니다 ... 이것이 작동하도록 허용할까요? 그것이 매개 변수화 여야한다는 것을 감안할 때 Enum, 유일한 선택은입니다 Enum<Season>, 당신이 가질 수 있도록 :

Season extends Enum<Season>
Enum<Season> implements Comparable<Season>

그래서 Enum 같은 유형에서 매개 변수화됩니다 Season. 초록 Season 그리고 당신은 그 매개 변수를 얻습니다 Enum 만족하는 모든 유형입니다

 E extends Enum<E>

Maurice Naftalin (공동 저자, Java 제네릭 및 컬렉션)

이것은 간단한 예제와 하위 클래스에 대한 사슬 된 메소드 호출을 구현하는 데 사용할 수있는 기술로 설명 할 수 있습니다. 아래 예에서 setName 반환 a Node 따라서 체인은 작동하지 않습니다 City:

class Node {
    String name;

    Node setName(String name) {
        this.name = name;
        return this;
    }
}

class City extends Node {
    int square;

    City setSquare(int square) {
        this.square = square;
        return this;
    }
}

public static void main(String[] args) {
    City city = new City()
        .setName("LA")
        .setSquare(100);    // won't compile, setName() returns Node
}

그래서 우리는 일반 선언에서 하위 클래스를 참조 할 수 있도록 City 이제 올바른 유형을 반환합니다.

abstract class Node<SELF extends Node<SELF>>{
    String name;

    SELF setName(String name) {
        this.name = name;
        return self();
    }

    protected abstract SELF self();
}

class City extends Node<City> {
    int square;

    City setSquare(int square) {
        this.square = square;
        return self();
    }

    @Override
    protected City self() {
        return this;
    }

    public static void main(String[] args) {
       City city = new City()
            .setName("LA")
            .setSquare(100);                 // ok!
    }
}

당신이 그것이 무엇을 의미하는지 궁금해하는 유일한 사람은 아닙니다. 보다 혼돈 자바 블로그.

"클래스 가이 클래스를 확장하면 매개 변수 E를 전달해야합니다. 매개 변수 E의 경계는 동일한 매개 변수 e 로이 클래스를 확장하는 클래스 용입니다."

이 게시물은 '재귀적인 일반 유형'의 이러한 문제를 완전히 명확히했습니다. 이 특정 구조가 필요한 다른 사례를 추가하고 싶었습니다.

일반 그래프에 일반 노드가 있다고 가정합니다.

public abstract class Node<T extends Node<T>>
{
    public void addNeighbor(T);

    public void addNeighbors(Collection<? extends T> nodes);

    public Collection<T> getNeighbor();
}

그런 다음 특수 유형의 그래프를 가질 수 있습니다.

public class City extends Node<City>
{
    public void addNeighbor(City){...}

    public void addNeighbors(Collection<? extends City> nodes){...}

    public Collection<City> getNeighbor(){...}
}

당신이 보면 Enum 소스 코드에는 다음이 있습니다.

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    } 
}

먼저, 무엇을 하는가 E extends Enum<E> 평균? 이는 유형 매개 변수가 Enum에서 확장되는 것이며 원시 유형으로 매개 변수화되지 않은 것을 의미합니다 (자체적으로 매개 변수화 됨).

열거가있는 경우 관련이 있습니다

public enum MyEnum {
    THING1,
    THING2;
}

내가 올바르게 아는 경우

public final class MyEnum extends Enum<MyEnum> {
    public static final MyEnum THING1 = new MyEnum();
    public static final MyEnum THING2 = new MyEnum();
}

따라서 MyEnum은 다음과 같은 방법을 수신한다는 것을 의미합니다.

public final int compareTo(MyEnum o) {
    Enum<?> other = (Enum<?>)o;
    Enum<MyEnum> self = this;
    if (self.getClass() != other.getClass() && // optimization
        self.getDeclaringClass() != other.getDeclaringClass())
        throw new ClassCastException();
    return self.ordinal - other.ordinal;
}

그리고 더 중요한 것은

    @SuppressWarnings("unchecked")
    public final Class<MyEnum> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<MyEnum>)clazz : (Class<MyEnum>)zuper;
    }

이것은 만든다 getDeclaringClass() 적절한 곳으로 캐스팅 Class<T> 물체.

명확한 예는 내가 대답 한 것입니다. 이 질문 일반적인 경계를 지정하려면이 구조를 피할 수없는 경우.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top