public class Solution {
private String name;
Solution(String name) {
this.name = name;
}
private String getName() {
return name;
}
private void sout()
{
new Solution("sout")
{
void printName()
{
System.out.println(getName());
}
}.printName();
}
public static void main(String[] args) {
new Solution("main").sout();
}
}
The method of an anonymous class behaves unexpectedly.
How to make method sout to print "sout", now it prints "main"?
The problem is that String getName() is private.
What this means is that it is inaccessible to methods of derived classes.
However, the anonymous derived class is not only derived, but it is also an inner class. As such, the class has access to private members of the outer class. That is why main gets printed, not sout.
All you need to do to make this work is to make the method non-private: default access, protected, or public would work fine.
Demo.
You would use
System.out.println(super.getName());
You have an anonymous inner class Solution inside a Solution, so getName() implicitly refers to the outer instance because the method is private.
You could also make getName protected instead of private.
The explanation is a bit ornery. getName is visible to the anonymous class because of scope, but since it's private, the anonymous class can't normally refer to getName on itself because it's actually a subclass.
The really strange case of this is when you have a static nested subclass:
class Example {
private void sayHello() {
System.out.println();
}
static class Subclass extends Example {
Subclass() {
// This is a compiler error
// because it tries to call sayHello()
// on an enclosing instance which doesn't
// exist (as if Subclass is an inner class).
sayHello();
}
}
}
I walked through the specification in my answer to a question asking about the static case, which also explains why "main" gets printed here: https://stackoverflow.com/a/28971617/2891664.
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;
}
}
It's been a rather long time since I've messed around with Java Abstraction and/or Interfaces, but I'm coming back to it now for a project and something is getting on my nerves. Below is a snippet of my code.
public class A {
private static String name = "None";
private static String description = "No description";
public A() {}
public A(User user) {
user.setData(this);
}
public static String getName() {
return name;
}
public static String getDescription() {
return description;
}
}
public class B extends A {
private static String name = "B";
private static String description = "This is B";
public B() {}
public B(User user) {
super(user);
}
}
public class User {
private A a;
public void setData(A a) {
this.a = a;
}
public A getData() {
return a;
}
}
When I use B.getName() I expect it to return "B" but it's instead returning "None".
Now I'm obviously doing something wrong, and searching around didn't help a bit. I'm fairly positive that this is possible someway, unless I'm getting confused with another language.
Could someone please point me in the right direction? Thanks.
You called the getName method on the class B. B doesn't have a static method called getName, so it looks for it in the superclass, A, which does.
Maybe you expect B's version of name to override A's? Variables don't get overridden. A is accessing the static variable name defined on A, that the method was originally called on B doesn't affect that.
Inheritance and static methods don't work well together. OO concepts like polymorphism rely on runtime dispatching, the word static should imply the opposite of that. With polymorphism the program works at a high level of abstraction, referring to the objects by a super type and letting the subclasses work out the details. With static methods you have to refer to the specific subclass you want the method called on, so you don't have that level of abstraction.
Welcome back to Java again.
You are using static variable in class A and B. These variables are associated with class instead of the objects.
If you change your method to get name from the User, it will work as you are expecting.
You need to override the method getName():
public class B extends A {
private static String name = "B";
private static String description = "This is B";
public B() {}
#Override
public static String getName() {
return name;
}
public B(User user) {
super(user);
}
}
The problem you are facing lies in the definition of the methods getName and getDescription: They are defined in class A as static members. This means that even when calling B.getName() the actual call is A.getName() and there the static member variable value of name is set to None.
When thinking about inheritance you have be careful what you declare as static. This has nothing to do with Interfaces or abstract classes.
public class A {
protected String name = "None";
protected String description = "No description";
public A() {}
public A(User user) {
user.setData(this);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
}
public class B extends A {
public B() {
name = "B";
description = "This is B"
}
public B(User user) {
super(user);
}
}
public class User {
private A a;
public void setData(A a) {
this.a = a;
}
public A getData() {
return a;
}
}
With the protected keyword you can access the fields from the extending class.
See also:
http://www.javatpoint.com/static-keyword-in-java
https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
A couple of things to note in your class :
name and description are static variables in both A and B
getName is a static method in A
static variables are bound to the class and static methods can't be overridden
This is the expected behavior since getName() method of class A has access to member variable of its own class that is "name" of class A. It is NOT because of name is static even if you make it non-static and you access it as shown in below code snippet it would return "None". Remember that only methods get overridden not member variables. So "name" of class B is not overriding "name" of class "A".
B b = new B();
System.out.println(b.getName()); --> "None" ("name" is non-static)
----------------------------------------------
System.out.println(B.getName()); --> "None" ("name" is static)
Also, if you want to get "B" as output , override getName() method of class A in class B and make method and variable non-static.
I am trying to understand how the below prints HelloWorldExtendedHelloWorld,false. I would expect it to print "true" since the whichMethod is overridden in the ExtendedHelloWorld class. If both methods were public and static, then I think it would make more sense since then both the parent and the child method would exist and I would be calling the parent method because I am using the HelloWorld reference. In this case, however, the methods are not static - so I was expecting then to be overridden. Anyway, the parent method is private, how can it be called from the outside? Can someone please help? Thanks!
public class HelloWorld {
public HelloWorld() {
System.out.print("HelloWorld");
}
public HelloWorld(int age) {
System.out.print("HelloWorldAge");
}
private boolean whichMethod() {
return false;
}
public static void main(String[] args) {
HelloWorld example = new ExtendedHelloWorld(5);
System.out.println("," + example.whichMethod());
}
}
class ExtendedHelloWorld extends HelloWorld {
public ExtendedHelloWorld(int age) {
System.out.print("ExtendedHelloWorld");
}
public boolean whichMethod() {
return true;
}
}
You're not extending the whichMethod method and in fact can't extend it, since it's private. Also, it's not being called "externally". The main method is within the class, and so the private method is visible to main. If the main method was elsewhere, your code would not compile, since example is a HelloWorld variable, and the private whichMethod within it would not be visible.
For a particular program, I essentially have an abstract superclass with several different subclasses. However, I'm having trouble with field shadowing as illustrated below.
abstract class Super {
String name;
String getName() {
return name;
}
}
Now I create subclasses that each have their own "name".
class Sub extends Super {
name = "Subclass";
}
However, creating instances of the subclass, and then calling the inherited method getName() will yield null due to field shadowing.
Is there an easy way to avoid this problem, and to allow subclasses to each have a unique field that can be accessed by an inherited method?
Make the field visible in the child class and initialize it in the subclass constructor or in a subclass instance initializer.
You might try this mechanism (bonus left to reader, extend code to get the name of the class directly). The code use the Abstract classes constructor to set the name. You could also define a setName function in the Super class and use that.
Super class (abstract)
package stackShadow;
public abstract class Super {
String name;
public Super(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Shadow1 class first subclass
package stackShadow;
public class Shadow1 extends Super {
public Shadow1() {
super("Shadow1");
}
}
Shadow2 class second subclass
package stackShadow;
public class Shadow2 extends Super {
public Shadow2() {
super("Shadow2");
}
}
Test class to test getName
package stackShadow;
public class Test {
public static void main(String[] args) {
Shadow1 one = new Shadow1();
Shadow2 two = new Shadow2();
System.out.println("Name for one is: " + one.getName());
System.out.println("Name for two is: " + two.getName());
}
}