In Java, Are Enum Types Inside a Class Static

In Java, are enum types inside a class static?

Yes, nested enums are implicitly static.

From the language specification section 8.9:

Nested enum types are implicitly
static. It is permissable to
explicitly declare a nested enum type
to be static.

Enums defined in a class is a static nested class?

The JLS says

An enum declaration specifies a new enum type, a special kind of class type.

So it looks like the word from Oracle is that enums are classes.

If you declare an enum inside another class, then yes, it's an inner class. And enums are always static, so yes, it's fair to call an enum a static inner class (or nested class) when it's declared in another class.

Are inner classes in enums always static in Java?

static keyword is not redundant. You may create a static nested class (with the static keyword) or an inner class (without it). In the first case the class won't be assigned to any particular enum value. In the second case, instances of the inner class need to have an enclosing instance - one of the enum values:

public class Test {
public static void main(String[] args) {
MyEnum.VALUE_1.createInnerObject().showName();
MyEnum.VALUE_2.createInnerObject().showName();
}

public enum MyEnum {
VALUE_1, VALUE_2;

public MyInnerClass createInnerObject() {
return new MyInnerClass();
}

private class MyInnerClass {
public void showName() {
System.out.println("Inner class assigned to " + MyEnum.this + " instance");
}
}
}
}

In the example above you can't create an instance of the MyInnerClass directly from the MyEnum:

new MyEnum.MyInnerClass(); // this will fail

In order to do this, you need to have a static nested class, but then you can't use something like MyEnum.this.

Are java enum variables static?

Yes, instances are implicitly static and final. This means that the code is unwise. Imagine two threads both calling SINGLE.setOperation(Type); you will have no confidence in what you are calling.

From the Java Language Specification, Section 8.9:

Enum types (§8.9) must not be declared abstract; doing so will result in a compile-time error.

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

It is a compile-time error to explicitly declare an enum type to be final.

Nested enum types are implicitly static. It is permissible to explicitly declare a nested enum type to be static.

And in the next section:

The body of an enum type may contain enum constants. An enum constant defines an instance of the enum type.

Because there is only one instance of each enum constant, it is permissible to use the == operator in place of the equals method when comparing two object references if it is known that at least one of them refers to an enum constant.

Static enum vs. Non-static enum

All enums are effectively static. If you have a nested enum, it is much the same as a static class.

All classes are lazily loaded (enums or otherwise) however when they are loaded they are loaded all at once. i.e. you can't have a few constants loaded but not others (except in the middle of class initialization)

Java allows certain modifiers to be implicit to avoid having to declare them all the time. This means that adding a modifier doesn't necessarily do anything other than provide a longer way of writing the same thing.

Default modifiers for

class field/method/nested class - package local, non-final, non-static

enum and nested enum - package local, final and static

interface field - public static final

interface method - public abstract

nested class in an interface - public static, non-final

Note: while static is optional for an enum it is always static. However, final cannot be set for an enum even though it is always notionally final (Technically you can have subclasses with overridden implementations for constants)

EDIT: The only place you need to use static with enum is with import static of an enum's value. Thank you @man910

Are enum types declared in a class implicitly static?

Yes, it is. The language specification even says so. From the JLS section 8.9 (enums):

Nested enum types are implicitly static. It is permissable to explicitly declare a nested enum type to be static.

Private enums and static fields in the enclosing class

This is a bit all over the place in the JLS. The When Initialization Occurs chapter states

The intent is that a class or interface type has a set of initializers
that put it in a consistent state, and that this state is the first
state that is observed by other classes. The static initializers and
class variable initializers are executed in textual order, and may not
refer to class variables declared in the class whose declarations
appear textually after the use, even though these class variables are
in scope (§8.3.3). This restriction is designed to detect, at compile
time, most circular or otherwise malformed initializations.

That bold snippet refers to the class directly containing the access.

enum types are defined in the Java Language Specification, here

An enum declaration specifies a new enum type, a special kind of class type.

The fields you access in the Baz constructor

Baz(String description) {
// Can access static fields from before the enum
first.add(description);

// Can access static fields from _after_ the enum
second.add(description);
}

are not class variables declared in the class, the enum type Baz. The access is therefore allowed.

We can go even deeper into the detailed class initialization procedure, which explains that each class (class, interface, enum) is initialized independently. However, we can create an example that sees yet-to-be-initialized values

public class Example {
public static void main(String[] args) throws Exception {
new Bar();
}
}

class Bar {
static Foo foo = Foo.A;
static Integer max = 42;

enum Foo {
A;

Foo() {
System.out.println(max);
}
}
}

This will print null. The access to max is allowed in the enum type's constructor although our program execution reached the access before max was initialized. The JLS warns against this

The fact that initialization code is unrestricted allows examples to
be constructed where the value of a class variable can be observed
when it still has its initial default value, before its initializing
expression is evaluated, but such examples are rare in practice. (Such
examples can be also constructed for instance variable initialization
(§12.5).) The full power of the Java programming language is available
in these initializers; programmers must exercise some care.


Your original Foo example introduces an extra rule, defined in the chapter on Enum Body Declarations .

It is a compile-time error to reference a static field of an enum type
from constructors, instance initializers, or instance variable
initializer expressions of the enum type, unless the field is a
constant variable (§4.12.4).

That rule blocks your Foo snippet from compiling.

enum constants translate to public static final fields. These appear textually first in the enum type definition and are therefore initialized first. Their initialization involves the constructor. The rules exists to prevent the constructor from seeing uninitialized values of other class variables that will necessarily be initialized later.

Nested Java enum definition - does declaring as static make a difference?

No, it makes no difference. However the reason is not because it is a member declaration inside an interface, as Jon says. The real reason is according to language spec (8.9) that

Nested enum types are implicitly
static. It is permissable to
explicitly declare a nested enum type
to be static.

At the following example static does not make any difference either (even though we have no interface):

public class A {
enum E {A,B};
}

public class A {
static enum E {A,B};
}

Another example with a nested private enum (not implicitly public).

public class A {
private static enum E {A,B}
}

Nested enum is static?

Your declaration of method() is in the wrong place. You declare it in the constant body. But it doesn't override anything. It belongs in the enum body, not the instance body.

The instance subtype is declared in the static initializer for the enum constant. Since the context is static it does not have access to the enum instance variables.

Your enum declaration is not static, it is top-level, and top-level classes cannot be static.

Constant bodies define an implicit nested anonymous subclass of the enum, and do not constitute nested enums as meant by the JLS. Each constant is of a different anonymous subtype of the enum you're declaring, which subtype is not static. However, the subtype is declared in a static context, so that's why the code can't reach the instance variable.

EDIT: Useful references from the JLS

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.9.1
"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. Instance methods declared in these class bodies may be invoked outside the enclosing enum type only if they override accessible methods in the enclosing enum type (§8.4.8)."

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.9.5
"An anonymous class declaration is automatically derived from a class instance creation expression by the Java compiler. An anonymous class is never abstract (§8.1.1.1). An anonymous class is always implicitly final (§8.1.1.2). An anonymous class is always an inner class (§8.1.3); it is never static (§8.1.1, §8.5.1)."

Is the enum inside a class static?

This

enum Value: char
{
UP, RIGHT, DOWN, LEFT
};

this is a declaration of a type. It is not a data member of the enclosing class. The class has only this private data member.

Value value_;

of the enumeration data.

An enumerations declaration declares named enumerators. But they in turn are not data members of the enclosing class.

It is the same if you will declare a nested structure inside a class. For example

struct A
{
struct B
{
int x = 10;
};

B b;
};

Here is only one data member of the class A that is B b. The data member inside the structure declaration only provides the declaration of the structure B.



Related Topics



Leave a reply



Submit