私は Java ジェネリックをかなりよく理解していると思っていましたが、java.lang.Enum で次のことに遭遇しました。
class Enum<E extends Enum<E>>
この型パラメータをどのように解釈するかを誰か説明してもらえますか? 同様の型パラメータが使用できる他の例を提供してくれたらボーナスポイントです。
ベストアンサー1
これは、enum の型引数が、同じ型引数を持つ enum から派生する必要があることを意味します。これはどのように実現できるでしょうか? 型引数自体を新しい型にすることで実現できます。つまり、StatusCode という enum がある場合、次のコードと同等になります。
public class StatusCode extends Enum<StatusCode>
ここで制約を確認すると、Enum<StatusCode>
次のようになりますE=StatusCode
。確認してみましょう: E
extendしますかEnum<StatusCode>
? はい! 大丈夫です。
これのポイントは何だろうと自問しているかもしれませんね :) つまり、これは Enum の API がそれ自体を参照できることを意味します。たとえば、 をEnum<E>
実装すると言うComparable<E>
ことができます。基本クラスは比較を行うことができます (列挙型の場合) が、正しい種類の列挙型同士のみを比較することを確認できます。 (編集: まあ、ほぼそうです - 下部の編集を参照してください。)
私は ProtocolBuffers の C# ポートで同様のものを使用しました。「メッセージ」(不変) と「ビルダー」(可変、メッセージの構築に使用) があり、これらは型のペアとして提供されます。関連するインターフェイスは次のとおりです。
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 のユーザーが実際にこれを気にする必要がないのは良いことです。これは恐ろしく複雑で、現在の状態に到達するまでに数回の反復が必要でした。
編集:これは、それ自体は問題ないが同じ型ではない型引数を使用する奇妙な型を作成することを妨げるものではないことに注意してください。目的は、右あなたを守るのではなく、間違っている場合。
したがって、Java で「特別に」処理されない場合はEnum
、(コメントに記載されているように) 次の型を作成できます。
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Second
...Comparable<First>
ではなく、を実装しますが、それ自体は問題ありません。Comparable<Second>
First