0

This is an academic question intended to better understand generics behave in this scenario.

The Enum type is described as "the common base class of all Java language enumeration types". Its definition is:

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

} 

Now, I could define a field with this definition:

public class MyClass { 
   public Enum<MyEnum> field;
}

All fine. Now, take it one step further. Since Enum<MyEnum> is apparently equivalent to MyEnum that would leave me to believe that according to the definition I also could write:

public class MyClass { 
   public Enum<Enum<MyEnum>> field;
}

But now the compiler actually stops me: Type parameter 'java.lang.Enum' is not within its bound; should extend 'java.lang.Enum<MyEnum>> which it does according to the definition since it still satisfies: E extends Enum<E>. Of course, there are all kinds of reasons why you would not allow such recurring (or perhaps better, incurring) construction, but the one given does feel wrong to me.

On the other hand, if I were to define a class like this (in analogue to the definition of the Enum)

public class Wrapper<T extends Number> { 
} 

I would be able to write a class:

public class MyClass { 
   // satisfies the upper bound
   public Wrapper<Integer> field1;

   // also satisfies the upper bound
   public Wrapper<Number> field2;
}

Am I overlooking something or is my analysis misguided?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Sjaak
  • 3,602
  • 17
  • 29
  • 5
    Sorry if I misunderstand the problem, but can ```public MyEnum field``` work for you? – Kaj Hejer Mar 28 '21 at 10:07
  • 1
    *"I could define a field with this definition: `public Enum field`"* --- Why would you? Why not just define it as `public MyEnum field`, since `MyEnum extends Enum`, and will be the **only** class ever to do so. – Andreas Mar 28 '21 at 10:16
  • 1
    It is not about practical solutions. It's for understanding the language better. – Sjaak Mar 28 '21 at 11:06

2 Answers2

6

I take it this is an academic question. You're not actually writing code like this, you just want to understand the language better, right? Because in real code you'd of course simply write:

public MyEnum myField;

In that spirit—

Since Enum<MyEnum> is apparently equivalent to MyEnum...

They're not equivalent. MyEnum is a subclass of Enum<MyEnum>. The autogenerated class is something like:

public final class MyEnum extends Enum<MyEnum> {
    ...
}

That means you can't keep expanding the declaration with Enum<Enum<MyEnum>>. You could write this, if you so desired:

public Enum<? extends Enum<MyEnum>> field;

That would compile, and the recursive possibilities end there.

What I understand of an upper bound X in T extends X that it includes X and its subclasses. So Enum<Enum> should be allowed but it isn't.

Let's take a look at exactly what E is, the E from here:

public abstract class Enum<E extends Enum<E>>

When you write Enum<Enum<MyEnum>>, E is Enum<MyEnum>. Does this E match the constraint E extends Enum<E>? We need to substitute E with Enum<MyEnum>.

E extends Enum<E>?
^              ^

Enum<MyEnum> extends Enum<Enum<MyEnum>>?
^^^^^^^^^^^^              ^^^^^^^^^^^^

Now let's answer a couple related but subtly different questions:

  • Does MyEnum extend Enum<MyEnum>? Yes. The autogenerated code I listed above shows this to be the case.

  • Does Enum<MyEnum> extend Enum<MyEnum>? Yes. As you correctly describe in your Number example, a class is considered to be a subclass of itself as far as the extends keyword is concerned.

  • And now the question we're concerned with here and now: Does Enum<MyEnum> extend Enum<Enum<MyEnum>>? No, it doesn't. This is the relation that would need to hold in order for the code you tried to work. It doesn't hold, and that's why your code doesn't compile.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Yes.. it is academic. And no.. most certainly I would not write code like this :) . But I'm involved in building an annotation processor which requires matching types. And we should be able to cover all scenarios. That's why I'd like to understand why my reasoning goes wrong. I need to think a more on your answer. Suppose a class: `public class Wrapper {}` . I would be able to create a field like this: `public class MyType{ public Wrapper field; }` right? The upper bound includes `Number` as well without resorting to wildcards. – Sjaak Mar 28 '21 at 10:42
  • I extended my example, just to make clear that it's an academic question. I understand that `MyEnum`is a subclass of `Enum ` but that still satisfies the upper bound, right. Its inclusive (hence my example with `Number`). – Sjaak Mar 28 '21 at 11:01
  • So what I meant, the argument of: `Enum>` is `Enum` or raw `Enum`. What I understand of an upper bound X in `T extends X` that it includes X and its subclasses. So `Enum` should be allowed but it isn't. And its here that I don't understand how it differs from my `Number` example. – Sjaak Mar 28 '21 at 15:05
  • Your answer is perfectly clear and it really helped me a lot. Thanks a lot for the time you invested. Though for me the aha moment came with the answer of @Andreas above. The part that confused was the `extends` bound. After all, (raw) `Enum` is in the bounds of `E extends Enum`. But it's the generic type parameter `X` `Enum` that spoils it. – Sjaak Mar 29 '21 at 06:36
2

With Enum<Enum<MyEnum>>, it makes E equal to Enum<MyEnum>.

The bound E extends Enum<E> therefore requires that Enum<MyEnum> must extend Enum<Enum<MyEnum>>, which it doesn't, and hence is rejected by the compiler.


Remember, Enum is the implicit superclass of an enum.

When you write enum MyEnum { ... }, what you get is really class MyEnum extends Enum<MyEnum> { ... }.

Which makes E equal to MyEnum.

The bound E extends Enum<E> therefore requires that MyEnum must extend Enum<MyEnum>, which it does, so the compiler is happy.

Andreas
  • 154,647
  • 11
  • 152
  • 247