Why can enum implementations not access private fields in the enum class - java

I just answered this question by saying how to solve the compilation problem:
How to use fields in java enum by overriding the method?
But what I don't understand is why the error is happening in the first place.
Here is the example written as an enum:
public enum MyEnum {
FIRST {
#Override
public String doIt() {
return "1: " + someField; //error
}
},
SECOND {
#Override
public String doIt() {
return "2: " + super.someField; //no error
}
};
private String someField;
public abstract String doIt();
}
Here is the exact same thing as abstract classes
abstract class MyClass {
class FIRST extends MyClass {
#Override
public String doIt() {
return "1: " + someField; //no error
}
};
class SECOND extends MyClass {
#Override
public String doIt() {
return "2: " + super.someField; //no error
}
};
private String someField;
public abstract String doIt();
}
In the case of FIRST within the enum implementation it cannot access someField. However in the abstract class case it can.
Additionally adding super fixes the problem, as does removing the private modifier on the field.
Does anyone know why this slight quirk in the behaviour is happening?

Your abstract class is not equivalent to your enum, since enums are implicitly public static final. Thus, you'll observe the same behavior if you use:
abstract class MyClass {
static class FIRST extends MyClass {
#Override
public String doIt() {
return "1: " + someField; // error
}
};
static class SECOND extends MyClass {
#Override
public String doIt() {
return "2: " + super.someField; // no error
}
};
private String someField;
public abstract String doIt();
}
As explained in http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html, chapter "Static Nested Classes":
A static nested class cannot refer directly to instance variables or
methods defined in its enclosing class: it can use them only through
an object reference.
Thus the need of super. You could also use this if the field were protected rather than private.

When an identifier is resolved, Java prefers the lexical scope over inherited members. So when you have an inner class that extends the outer class and use a field of the outer class without using this or super, the field of the outer instance is accessed which fails if the inner class is static as there is no outer instance then. In contrast, when using super you are explicitly accessing the inherited member. Note that enum classes are implicitly static. You can even use this to access the inherited member but you have to use ((MyClass)this).someField to access it if it’s declared private.

Class FIRST is an inner class of MyClass and also a sub class. The reason you do not see an error when accessing someField in it is because you are accessing the someField of the outer class, not the super class.
class MyClass {
class FIRST extends MyClass {
#Override
public String doIt() {
super.someField = "super";
return "1: " + someField;
}
};
private String someField = "outer";
public String doIt(){return "";}
public static void main(String[] args) {
System.out.println(new MyClass().new FIRST().doIt());
}
}
Prints 1: outer.
In the other case your enum constants behave as static nested sub classes, not inner classes, so they do not have a reference to the outer class, only their super class.

I disagree with the accepted answer.
The enum const declaration is implicit public static final, but not the class the enum const belongs to.
From JSL Chapter 8.Classes
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.
And what the 'rules of anonmous classes'?
From JSL Chapter 15:
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).
And if the enum equivalent class is a static class, how to explain the following error?
public enum MyClass {
First {
public static int b; //(2)Illegal static declaration in inner class
};
}
But why a inner class can't access the outer class's field?
A possible enum equivalent class may looks like following, which gives the same error as a enum class:
abstract class MyClass {
private int someField;
static {
class First extends MyClass {
public void method() {
System.out.println(someField);
}
private static int b;
}
}
}
More:
Nested enum is static?
How is enum implemented?

Related

Why can’t this static inner class call a non-static method on its outer class?

I'm currently reading Effective Java by Joshua Bloch and I love it! But on page 112 (Item 24) Bloch writes:
A static member class is the simplest kind of nested class. It is best
thought of as an ordinary class that happens to be declared inside
another class and has access to all of the enclosing class’s members,
even those declared private.
And that really confuses me. I would rather say:
A static member class is the simplest kind of nested class. It is best
thought of as an ordinary class that happens to be declared inside
another class and has access to all of the enclosing class’s static members,
even those declared private.
Here is a snippet that illustrates my understanding of the quote:
public class OuterClass {
public void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
public void sayHello() {
printMessage("Hello world!"); //error: Cannot make a static reference to the non-static method printMessage(String)
}
}
}
You can see that InnerClass's sayHello method does not have access to OuterClass's printMessage method as it is declared in a static inner class while the printMessage method is an instance method. It looks like the author suggests that a static member class can access nonstatic fields of the enclosing class. I am convinced that I have misunderstood something in his last sentence but I cannot figure out what. Any help will be appreciated!
edit: I changed the visibility of the two methods because it is irrelevant to my question. I'm interested in static members, not private members.
Just because InnerClass is static, doesn't mean it couldn't obtain a reference to an instance of OuterClass through other means, most commonly as a parameter, e.g.
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
private void sayHello(OuterClass outer) {
outer.printMessage("Hello world!"); // allowed
}
}
}
If InnerClass had not been nested inside OuterClass, it would not have had access to the private method.
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
}
class InnerClass {
private void sayHello(OuterClass outer) {
outer.printMessage("Hello world!"); // ERROR: The method printMessage(String) from the type OuterClass is not visible
}
}
Note the error message. It's not saying you don't have access. It's saying the method cannot be called. Instance methods don't mean anything without an instance to
call them on. What the error message is telling you is that you don't have that instance.
What Bloch is telling you is that if that instance existed, code in the inner class could call private instance methods on it.
Say we have the following class:
public class OuterClass {
public void publicInstanceMethod() {}
public static void publicClassMethod() {}
private void privateInstanceMethod() {}
private static void privateClassMethod() {}
}
If we try to call those private methods from some random class, we can't:
class SomeOtherClass {
void doTheThing() {
OuterClass.publicClassMethod();
OuterClass.privateClassMethod(); // Error: privateClassMethod() has private access in OuterClass
}
void doTheThingWithTheThing(OuterClass oc) {
oc.publicInstanceMethod();
oc.privateInstanceMethod(); // Error: privateInstanceMethod() has private access in OuterClass
}
}
Note that those error messages say private access.
If we add a method to OuterClass itself, we can call those methods:
public class OuterClass {
// ...declarations etc.
private void doAThing() {
publicInstanceMethod(); // OK; same as this.publicInstanceMethod();
privateInstanceMethod(); // OK; same as this.privateInstanceMethod();
publicClassMethod();
privateClassMethod();
}
}
Or if we add a static inner class:
public class OuterClass {
// ...declarations etc.
private static class StaticInnerClass {
private void doTheThingWithTheThing(OuterClass oc) {
publicClassMethod(); // OK
privateClassMethod(); // OK, because we're "inside"
oc.publicInstanceMethod(); // OK, because we have an instance
oc.privateInstanceMethod(); // OK, because we have an instance
publicInstanceMethod(); // no instance -> Error: non-static method publicInstanceMethod() cannot be referenced from a static context
privateInstanceMethod(); // no instance -> Error: java: non-static method privateInstanceMethod() cannot be referenced from a static context
}
}
}
If we add a non-static inner class, it looks like we can do magic:
public class OuterClass {
// ...declarations etc.
private class NonStaticInnerClass {
private void doTheThing() {
publicClassMethod(); // OK
privateClassMethod(); // OK
publicInstanceMethod(); // OK
privateInstanceMethod(); // OK
}
}
}
However, there's trickery going on here: a non-static inner class is always associated with an instance of the outer class, and what you're really looking at is:
private class NonStaticInnerClass {
private void doTheThing() {
publicClassMethod(); // OK
privateClassMethod(); // OK
OuterClass.this.publicInstanceMethod(); // still OK
OuterClass.this.privateInstanceMethod(); // still OK
}
}
Here, OuterClass.this is special syntax for accessing that outer instance. But you only need it if it's ambiguous, e.g. if the outer and inner classes have methods with the same name.
Note too that the non-static class can still do the things the static one can do:
private class NonStaticInnerClass {
private void doTheThingWithTheThing(OuterClass oc) {
// 'oc' does *not* have to be the same instance as 'OuterClass.this'
oc.publicInstanceMethod();
oc.privateInstanceMethod();
}
}
In short: public and private are always about access. The point Bloch is making is that inner classes have access that other classes don't. But no amount of access allows you to call an instance method without telling the compiler what instance you want to call it on.
The way you showed it requires inheritance. But methods and fields could be access in this way:
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
private void sayHello() {
OuterClass outer = new OuterClass();
outer.printMessage("Hello world!");
}
}
}
But, that the static inner class doesn't have access to the printMessage function doesn't have to do with that it is an inner class, but that it is static and can't invoke a non-static method. I think that the use of the word "static" you proposed was implicit in the first sentence. What he is pointing out, or chose to emphasize, is just that the inner class can still access private methods of its parent class. He might have just though it unnecessary or confusing to make the static/non-static distinction in the same sentence, too.
The way I see it, the text is absolutely right. Static member classes can access the private members of the enclosing classes (sort of). Let me show you an example:
public class OuterClass {
String _name;
int _age;
public OuterClass(String name) {
_name = name;
}
public static OuterClass CreateOuterClass(String name, int age) {
OuterClass instance = new OuterClass(name);
instance._age = age; // Notice that the private field "_age" of the enclosing class is visible/accessible inside this static method (as it would also be inside of a static member class).
return instance;
}
}

Why am I throwing no errors for calling object-specific methods/fields from inner classes?

I'm using something similar to the following code in one of my Java classes:
public class SomeClass {
private int someValue;
void incrementValue() {
someValue++;
}
public abstract static class InnerClass {
private final SomeClass toRunOn;
public InnerClass(SomeClass obj) {
toRunOn = obj;
}
public abstract void execute();
// To allow us to call this on a given instance
final SomeClass getObj() {
return toRunOn;
}
}
public final InnerClass called = new InnerClass(this) {
public final void execute() {
incrementValue(); // This is what I thought should be throwing an error
}
};
}
However, while I would expect this to throw a compiler error in the called field defining execute() due to me not giving incrementValue() an object to work on (which is why I allowed for passing this to the inner class), it is completely fine with it. I'm uncertain why this is not giving me an error, and further confused as to what instance it would be calling on.
Am I misunderstanding some form of reference calling here, or is something more subtle going on?
called is assigned an instance of an anonymous sub-class of InnerClass. Since it's an instance member, it is initialized when an instance of SomeClass is created.
Since it is declared in the body of SomeClass, it is an inner class of SomeClass and has access to the instance methods and members of SomeClass. incrementValue() will be executed on the instance of SomeClass for which the called member was initialized.
Perhaps it would be easier to understand if you replace the anonymous class with an equivalent regular inner class :
public class SomeClass {
....
class SubInnerClass extends InnerClass {
public final void execute() {
incrementValue();
}
}
public final InnerClass called = new SubInnerClass(this);
....
}

Are inner classes in enums always static in Java?

I have an enum class which contains an inner class in Java.
For example (In the real code, there are some methods declared on the enum that internally use the inner class):
public enum MyEnum{
VALUE_1,
VALUE_2;
private static class MyInnerClass // is static here needed or can it be removed?
{
}
}
PMD tells me that the 'static' modifier is not needed (Violation of the UnusedModifier rule). Is this correct or would it be a PMD bug?
Note: This question is not a duplicate, it is the inverse of what I ask here.
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.

Compiler errors when static abstract Inner class accesses outer class private fields java

I have a class with private fieds and also a static abstract inner class with the generic type extending the outer class type, that tries to access the outer class private fields but get's the following error:
- error: a has private access in Outer
- error: doSomething has private access in Outer
See code below:
public abstract class Outer extends SomeOuter
{
private Object a;
private void doSomething(){}
public static absract class Inner<T extends Outer> extends SomeOuter.SomeInner<T> {
public InnerMethod(T p) {
p.a; //error: a has private access in Outer
p.doSomething() //error: doSomething has private access in Outer
}
}
}
I'm compiling using jdk 1.7
Can anyone please tell me why am getting this error.
An Inner class can access private field of enclosing class and a static inner class can also access any private members of enclosing class .
The class itself isn't really "static"; there's no such thing as a static class. The
static modifier in this case says that the nested class is a static member of the outer
class. That means it can be accessed, as with other static members, without having
an instance of the outer class.
Since it is a static member , it is able to access outer class's private members , because within class private members are accessible.
eg.
class One
{
private int i=0;
class Two
{
void go()
{
System.out.println(new One().i); //accessible
}
}
}
class two
{
private int i=3;
static class one
{
void go()
{
System.out.println(new two().i); //accessible in static class
}
}
}
But here ,
Inner<T extends Outer> extends SomeOuter.SomeInner<T>
T is a class which extends Outer , doesn't mean it is inner.
That why it is giving error.
thats how private modifier works if you ever declare any method or variable as private than that things can not be accessed out side the class
A static embedded class is effectively an outer class. It can't access the private members of another class. See the accepted answer to:
Static nested class in Java, why?
Both the Object and the function you're trying to use are declared as private, which means they cannot be used outside the Object. If you want to use them in child classes as well, declare them as protected.
Changes the scope of the fields on the Outer class to protected so that classes extending Outer may access these fields.
public abstract class Outer extends SomeOuter
{
protected Object a;
protected void doSomething(){}
public static absract class Inner<T extends Outer> extends SomeOuter.SomeInner<T> {
public InnerMethod(T p) {
p.a; //error: a has private access in Outer
p.doSomething() //error: doSomething has private access in Outer
}
}
}
Thats what you have private modifier for. Though it is the inner class, it cannot access the private members of the outer class. So, declare it as protected, as you are extending the outer class to inner class

scope of private constructor in Nested Class

This is more of a puzzle than question. I have the following code:
public class PrivateBaseConstructor {
public static class BaseClass {
private BaseClass() {
}
}
public static class DerivedClass extends BaseClass {
public DerivedClass() {
super(); // 1*
}
}
}
Here the call for super(); at 1* is allowed even though the base class constructor is private. If we write the classes as separate classes in same package:
BClass.java
public class BClass {
private BClass() {
}
}
DClass.java
public class DClass extends BClass {
public DClass() {
super(); // 2*
}
The compiler rightly gives an error at 2* since the base class constructor is not visible.
Why doesn't the compiler throw an error in my first scenario when both the classes are declared static within one class?
if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.1
Because nested classes can see each others members. This has nothing to do with the static declarations. See the following example of your code with just nested inner classes (not static).
public class PrivateBaseConstructor {
public class BaseClass {
private BaseClass() {}
}
public class DerivedClass extends BaseClass {
public DerivedClass() {
super(); // 1*
}
}
public static void main(String[] args)
{
new PrivateBaseConstructor(). new DerivedClass();
}
}
Read more about nested classes here: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Because anything declared inside a class can access its private members, including inner classes. However, if you run PMD on your class, you'll find it suggests you change the visibility of the constructor to not-private.

Categories