2

Consider the following Enum classes:

public enum APlanet { VENUS () {public void stuff(){}}, EARTH () {public void stuff(){}}, MARS () {public void stuff(){}}; public abstract void stuff(); } public enum BPlanet { VENUS (), EARTH (), MARS (); } 

Then APlanet.MARS.getClass().isEnum() returns false whereas BPlanet.MARS.getClass().isEnum() returns true. Why? Notice that APlanet.getDeclaringClass().isEnum() correctly returns true.

Specifically, I'm trying to reliably test if an Object is Enum:

Object a = APlanet.MARS; Object b = BPlanet.MARS; a.getClass().isEnum() /* returns false */ b.getClass().isEnum() /* returns true */ 

yet

Enum.class.isAssignableFrom(a.getClass()); /* returns true */ 

It's a little confusing that the inner class APlanet.MARS is not an Enum yet you can assign it to an Enum, as in:

Enum<?> m = APlanet.MARS; 
2
  • Thanks for the fast response. How can I reliably test if an Object is an instance of an Enum? Commented Sep 14, 2013 at 21:44
  • What do you mean by that? Can you add an example? If you are in need to doing something like that, then I guess there is some issue with your design. Commented Sep 14, 2013 at 21:54

1 Answer 1

8

From JLS Section 8.9.1 - Enum Constants:

The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes; in particular it cannot contain any constructors.

You have declared the constant-specific class body in your first enum:

 MARS () {public void stuff(){}}; // The curly braces defines a class body 

This creates an anonymous class. So, MARS.getClass() will return the Class instance for this anonymous class, which is not an Enum.


This is similar to case where you create an instance of anonymous subclass of an interface, or any other class like this:

SomeInterface obj = new SomeInterface() { /** Method definitions **/ }; 

and then obj.getClass() wouldn't return SomeInterface but, ClassContainingThatDeclaration$1.

Notice that APlanet.getDeclaringClass().isEnum() correctly returns true

I suspect that should be - APlanet.MARS.getDeclaringClass().isEnum(). That would return true, as per the documentation of Enum#getDeclaringClass() method:

Returns the Class object corresponding to this enum constant's enum type. Two enum constants e1 and e2 are of the same enum type if and only if e1.getDeclaringClass() == e2.getDeclaringClass(). (The value returned by this method may differ from the one returned by the Object.getClass() method for enum constants with constant-specific class bodies.)


But I thought an enum can't be subclassed?

Now the doubt that can come to one's mind is, an enum can't be subclassed. So, how can the anonymous subclass of enum be created? How can it extend the enum? That's because, an enum is final unless it declares some constant-specific class body, as per JLS Section 8.9 - Enums:

An enum type is implicitly final unless it contains at least one enum constant that has a class body.

You still can't explicitly extend an enum:

Even though the constant-specific class body implicitly creates an anonymous sub-class, you can't explicitly extend an enum. As per JLS Section 8.1.4 - Superclasses and Subclasses:

It is a compile-time error if the ClassType names the class Enum or any invocation of it.

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

2 Comments

+1 It's this all over again :). And congrats on getting "Legendary"!
@Bohemian. Ah! Thanks :) Quite happy about it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.