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.
Related
What are the usages of adding onymous (not anonymous) class method in class body in enum's constant values declaration?
public enum Status {
SUCCESS("SUCCESS"){},FAILED("FAILED"){
class Test {
public void test() {
System.out.println("test");
}
}
};
private String code;
Status(String code) {
this.code = code;
}
How do I access/execute such method ? I find anonymous class example, which isn't recommended
As a recommendation, make your enum implement your interface to make the code more readable
I didn't find usages in JLS's Enum Constants section
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.
TL;DR It's hard to imagine a real-world situation where defining an inner class inside of an enum constant makes sense.
Let's start from your code example...
public enum Status {
SUCCESS("SUCCESS") {
},
FAILED("FAILED") {
class Test {
public void test() {
System.out.println("test");
}
}
};
private String code;
Status(String code) {
this.code = code;
}
}
As FAILED is an enum value with a body, it becomes an anonymous subclass of the Status enum class. And Test is defined inside this anonymous class. Because of the anonymous nature of its enclosing class, there's no way to express its name from outside of FAILED. It surely isn't Status.FAILED.Test.
So Test is mainly useful inside of FAILED (if FAILED's implementation is complex enough to warrant an inner class). Generally, I'd prefer enum constants to not become that complex, but that's a matter of style.
An access to Test from outside of FAILED is only possible through a superclass or interface that Test extends / implements, and only to methods exposed through that superclass or interface.
A (contrived) example showing both a usage inside and outside of FAILED, might be:
public class StatusTest {
enum Status {
FAILED{
class Test implements Runnable {
private String text = "Test " + System.currentTimeMillis();
#Override
public void run() {
System.out.println(text);
}
}
#Override
public Runnable getRunner() {
return new Test();
}
#Override
public void message() {
getRunner().run();
}
};
public abstract void message();
public abstract Runnable getRunner();
}
public static void main(String[] args) {
Status status = Status.FAILED;
status.message();
Runnable runner = status.getRunner();
runner.run();
}
}
(Added later)
Of course, in this example there's no reason why the Runnable should get a class name. I'd typically use a named inner class instead of an anonymous one only if it's
used in multiple places or
so complex that it would make the enclosing method unreadable.
That's always the same decision when introducing an anonymous vs. a named inner class. With enums there's even less reason to give the inner class a name, as this name isn't usable outside. So, if I were to see a code like above, I'd refactor it to use an anonymous class:
public class StatusTest {
enum Status {
FAILED {
#Override
public Runnable getRunner() {
return new Runnable() {
private String text = "Test " + System.currentTimeMillis();
#Override
public void run() {
System.out.println(text);
}
};
}
#Override
public void message() {
getRunner().run();
}
};
public abstract void message();
public abstract Runnable getRunner();
}
public static void main(String[] args) {
Status status = Status.FAILED;
status.message();
Runnable runner = status.getRunner();
runner.run();
}
}
In both cases, the inner class itself isn't visible to outside code, only inside the enum constant, and if the enum constant's implementation gets so complex that it warrants a named inner class, I'd surely refactor it, e.g. by delegating the complexity to some normal top-level 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;
}
}
What is the real time utility of non static fields inside static inner class?
Also, how instance creation of static inner class works :
class Outer {
static class Inner {
public final String text = "Inner";
}
}
public class A {
public static void main(String[] args) {
System.out.println(new Outer.Inner().text);
}
}
Just consider static inner class as normal class (just placed inside class instead package) and consider non-static inner class something like generic, based on instance of outer class.
when you extend a private class. Are the public and protected members of class become private. if not any explanation.
if you extend a nested private class, it wont change public/protected modifiers of the members. Here is an example :
public class Clazz {
private static class NestedClazz {
public int value = 123;
}
public static class NestedClazzExt extends NestedClazz {
}
}
you can now access the inherited member: value from outside
public static void main(String[] args) {
NestedClazzExt nestedClazz = new Clazz.NestedClazzExt();
System.out.println(nestedClazz.value);
}
you can create private class in side a class . We call it as Nested classe. Means a class inside a class. The Concept itself is saying that you can create private class in side another class. The private class will act like as data member to the outer class.
So, You can't extend the private class.
Based on your query I tried to prepare a simple class.
public class pvtClass {
private class As {
public String abc = "private attribute";
public void print(){
System.out.println("privateClass");
}
}
class Ab extends As{
public String ab = "extended attribute";
public void printAb(){
System.out.println("extended class");
print();
System.out.println(abc);
}
}
public static void main(String as[]){
Ab ab1 = (new pvtClass()).new Ab();
As as1 = (new pvtClass()).new As();
ab1.printAb();
as1.print();
System.out.println(as1.abc);
}
}
If you have a look at this class, I have a private class named "As" which has public attribute and public methods. I have another class named "Ab" which extends "As". I have written a main method to invoke the private attribute and methods.
below is the output for the code snippet:
extended class
privateClass
private attribute
privateClass
private attribute
There is a difference between the access of the members of a class and the access to the type itself.
public class C {
private class InnerP1 {
public void m() {
System.out.println("InnerP1.m()");
}
}
private class InnerP2 extends InnerP1 {
public void p() {
this.m();
System.out.println("InnerP2.p()");
}
}
public InnerP1 strange() {
return new InnerP2();
}
}
In this example, the interface I is visible from outside class C. The classes InnerP1 and InnerP2 are not visible from outside C. Jave itself makes not restrictions to the visibility of types you use in your public interface. The method strange() of class C returns a result of class InnerP1. Since outside of C we do not know anything about the class InnerP1 other than it is subtype of Object, the only thing we can do is use the result of strange() as an Object.
public class D {
public static void main(String[] args) {
C c = new C();
Object o = c.strange();
if(o.equals(c.strange())) {
System.out.println("Strange things are going on here!");
}
}
}
As #KnusperPudding pointed out already, the visiblity of public members is not changed, we might just not have enough knowledge of the type itself to access them.
Access to members cannot be restricted by sub-classing. When you mark a class as private then access via the class name is restricted i.e. to the same .java file, however once you have an instance of this class it can be accessed at least as easily as the super class.
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?