4

I have been trying to create enum that contains generic attribute, for example:

public enum SomeEnum {
    SOME_VALUE_1(SomeValue1.class),
    SOME_VALUE_2(SomeValue2.class);

    private final Class<T extends SomeValue> className;
}

SomeValue1 and SomeValue2 classes implement SomeValue interface. For some reason <T extends SomeValue> is marked with "Unexpected bound" error. If I replace T with ?, there is no error. But it is still puzzling me why it is happening when I use T.

Any help would be highly appreciated.

2 Answers 2

4

When you use T extends SomeValue in this way, you are referencing a type variable T that isn't defined, and you aren't allowed to define a type variable there. Only on type variable declarations are you allowed to define a bound such as T extends SomeValue.

On an interface or class, you could define T with the bound you want, but not on an enum. Enums are not allowed to be generic in Java.

You are probably getting the same error on the constructor you haven't shown that accepts a Class<T extends SomeValue> to assign to className. The same reason applies here too.

Using ? extends SomeValue is an upper-bounded wildcard. It basically means "a specific yet unknown type that is SomeValue or a subtype". This is appropriate here, because all you care about here is that the Class is for SomeValue or some implementation class.

Sign up to request clarification or add additional context in comments.

1 Comment

I am using Lombok, so didn't notice it in constructor, but it makes sense. Thank you very much for the explanation, now it is clear to me.
2

<? extends SomeClass> and <T extends SomeClass> are two very different syntaxes.

The first is a wildcard bound, part of a type argument:

TypeArguments:
  < TypeArgumentList >
TypeArgumentList:
  TypeArgument {, TypeArgument}
TypeArgument:
  ReferenceType 
  Wildcard
Wildcard:
  {Annotation} ? [WildcardBounds]
WildcardBounds:
  extends ReferenceType 
  super ReferenceType

The second is a type bound, part of a type parameter:

TypeParameter:
  {TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
  Annotation
TypeBound:
  extends TypeVariable 
  extends ClassOrInterfaceType {AdditionalBound}

What's the difference between a type parameter and a type argument? A type parameter, like a method parameter, occurs at e.g. a generic class/method declaration:

class Foo<T extends SomeClass> {} // "T extends SomeClass" is a type parameter
class Bar<T> {} // "T" is a type parameter

This is analogous to method parameters:

void foo(int i) {} // "int i" is a method parameter

A type argument, like a method argument, occurs where you use a generic class/method. For example, in a field declaration:

Foo<? extends SomeClass> foo; // "? extends SomeClass" is a type argument
Bar<String> // "String" is a type argument

This is analogous to method arguments that you pass when you call a method:

foo(1); // "1" is a method argument

So really, using T extends SomeClass where you should use ? extends SomeClass makes no sense. You are not declaring a new type variable here. You are merely constructing a generic type.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.