Having the following superclass:
public class SuperClass {
protected Integer a;
protected Integer b;
public void doSomething() {
this.a = 10;
}
public void doEverything() {
SuperClass.this.doSomething();
this.b = 20;
}
public static void main(String[] args) {
SuperClass instance = new SubClass();
instance.doEverything();
System.out.println(instance.a); //should print 10
System.out.println(instance.b);
}
}
And the following subclass:
public class SubClass extends SuperClass {
#Override
public void doSomething() {
super.doSomething();
super.a *= 10;
}
public void doEverything() {
super.doEverything();
this.b += 5;
}
}
Outputs:
100
25
So, SuperClass.this.doSomething(); is accessing SubClass's doSomething, but I need it to access the SuperClass's doSomething. In that case, I don't have the super keyword, because I'm already on super!
Is there a way to reference¹ the deep SuperClass.this.doSomething, so it would output 10 for the first output value?
¹ I'm interested on referencing: we could, of course, extract the SuperClass's doSomething to an auxiliar private method and access it directly.
If there is no way, does the situation where a superclass method needing to access its another (although overridden) method mean that my OOP design isn't correct? Why?
I assume you come to Java from C++ background. The languages are similar in concepts and in syntax, but they are different in the implementation.
You can achieve what I think is your intention also in Java, but the structure will look differently from C++.
In Java the construct SuperClass.this in your example is exactly the same as this, so SuperClass.this.doSomething(); is exactly what just doSomething() would be. So why does Java at all has the construct SuperClass.this? It has its meaning unrelated to the inheritance. It is useful in the context of nested classes.
Imagine a structure like this:
class A {
class B {
public void doSomething() {
// this here refers to an instance of the class B
System.out.println(this);
// We need to write is this way,
// because this hides the this reference to the instance of A.
// A.this is the instance of A where this is nested
System.out.println(A.this);
}
}
So how can you make sure to be able to have a method in a class that subclasses can override, and still be able to call the specific implementation?
Well, in the strict sense, you cannot. What you can do, is to create a final method, which cannot be overridden, and call it from a non-final method.
class SuperClass {
public void doSomething() {
doSuperClassyThing();
}
public final void doSuperClassyThing() { // cannot be overridden
...
}
}
A similar approach (with a bit different goal) you can see in the Template Method Pattern.
You cannot do what you want. The way polymorphism works is by doing what you are seeing.
That means there is no direct way to call SuperClass.doSomething() from SuperClass.doSomething() without going though SubClass.doSomething() unless you're working with an actual instance of SuperClass.
In some other languages you have power to tell how to handle this for example with keyword virtual in c++, but in java you don't have that option. All the method are being dynamically binded so you cannot do that. You can only not override or prevent it from being overriden at all.
The answer is that you can't refer to it. The only way to do this is the private helper method approach that you are aware of already.
If you want to know the reason why, I guess it's just because it would complicate the language for no reason; you can always get the same result by using a private helper method. The syntax SuperClass.this.doSomething() is already taken for something else. That means calling the method doSomething on the enclosing instance if SuperClass is an enclosing class.
If you ever find yourself on that situation, maybe you should rethink and consider that the class structure is not that correct yet.
Try to implement one of the following approaches:
Composition over Inheritance.
Creating a new Inheritance level (a class in the middle that has a reference to super).
Same as (2.), but using an inner class.
Extract the wanted method to a separate private one and call it where applicable.
Since (1.) wouldn't be as dry as the others, (4.) leaves a feeling of a workaround, and (2.) would require the creation of a new file and would reference outside SuperClass; I think the closest approach would be (3.), which is the only solution that in some way references super inside SuperClass (although it's actually referenced on a SuperClass inner class):
SuperClass.java:
public abstract class SuperClass {
protected Integer a;
protected Integer b;
public void doSomething() {
this.a = 10;
}
public abstract void doEverything();
public static class Impl extends SuperClass {
#Override
public void doEverything() {
super.doSomething();
this.b = 20;
}
}
public static void main(String[] args) {
SuperClass instance = new SubClass();
instance.doEverything();
System.out.println(instance.a); //prints 10
System.out.println(instance.b);
}
}
SubClass.java:
public class SubClass extends SuperClass.Impl {
#Override
public void doSomething() {
super.doSomething();
super.a *= 10;
}
#Override
public void doEverything() {
super.doEverything();
this.b += 5;
}
}
Related
I was asked this question in a recent interview. Looking to get some help.
Class A has foo() method triggered from constructor.
public class A {
public A() {
foo();
}
public void foo() {
System.out.println("In foo method in class A");
}
}
Class B overrides the foo method in class A.
public class B extends A {
#Override
public void foo() {
System.out.println("In foo method in class B");
}
}
Now if we create instance of class B the foo() method in B will be called.
A a = new B();
prints: "In foo method in class B"
Question: Lets say we own the class A and it is part of a jar file(abc.jar) and how do we make sure when class B is instantiated A.foo() is called instead of overridden B.foo()?
Conditions:
Imagine the jar is shared to other users and we cannot break client code my marking the method private/final.
Also calling super.foo() from class B is also not an option since we don't own class B and cannot restrict users.
public class A {
public A() {
fooInternal();
}
public void foo() {
fooInternal();
}
private final void fooInternal() {
System.out.println("In foo method in class A");
}
}
You can't make it invoke A.foo(), because that method is overridden. You can only make it invoke a method that A.foo() invokes, and that can't be overridden.
The more important point here is that you shouldn't ever invoke overrideable methods from a constructor.
Mark A's foo method as final. It is the only way.
In order to still allow B to also get a ping on initialization, the solution is a two-stage construct: A's constructor invokes the final foo() method, but as part of the foo() method, foo2, or subfoo, or whatever you want to call it, is also invoked, and that method is defined in A as a noop (does nothing).
Generally such a final init()-style method should also be private. Based on common logic: What are the odds that an 'init' operation is also a concept that external code could plausibly want to invoke a second time at some arbitrary later point in time? Highly unlikely, which is why it should be private. Once you do so, well, private methods are effectively inherently final, so that takes care of that:
class A {
public A() {
init0();
}
private final init0() {
// do stuff here - subclasses won't stop you.
init();
}
// B can override this if it wants.
protected void init() {}
}
I'm studying CS and we have questions about polymorphism that I cant wrap my mind around. Here is an example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
public BB(){
foo();
}
public void foo(){
System.out.print("BB:foo ");
}
public void goo(){
System.out.print("BB::goo ");
}
public static void main(String[] args){
// Code goes here
}
}
When in void main i add the line:
AA a = new BB();
it goes first AA constructor prints AA:foo but then goo() sends it to BB's goo, why so?
Simple polymorphism such as "Animal -> cat/spider/dog" is easy to understand but when it comes to this I'm just lost. Can you guys give me any tips how to read this code? What are the rules are?
EDIT: there is no #Override annotation because this is a question from an exam.
Explanation
public class AA {
private void foo() { ... }
^^^^^^^
}
Polymorphism is not applied to private methods. A subclass does not inherit private methods, so they cannot be overridden:
A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:
m is a member of the direct superclass of C.
m is public, protected, or declared with package access in the same package as C.
No method declared in C has a signature that is a subsignature of the signature of m.
Java Language Specification - 8.4.8. Inheritance, Overriding, and Hiding
Therefore, the foo() call from the A constructor doesn't invoke BB#foo, it calls AA#foo.
But the goo() call within AA#foo refers to the overridden method BB#goo. Here, with public methods, method overriding and polymorphism were applied.
It's a bit tricky, so I would recommend you put the #Override annotation everywhere it's supposed to be.
public class BB extends AA {
#Override // it doesn't compile - no overriding here
public void foo() { ... }
#Override // it does override
public void goo() { ... }
}
It also might be helpful to detect another problem:
Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.
If a method declaration in type T is annotated with #Override, but the method does not override from T a method declared in a supertype of T, or is not override-equivalent to a public method of Object, then a compile-time error occurs.
Java Language Specification - 9.6.4.4. #Override
Illustration
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation super();, an invocation of the constructor of its direct superclass that takes no arguments.
Java Language Specification - 8.8.7. Constructor Body
To put it simply,
public BB() {
foo();
}
turns into
public BB() {
super();
foo();
}
Keeping super(); in mind, we can make the next illustration:
new BB()
AA() // super(); -> AA constructor
A#foo() // private method call
B#goo() // polymorphic method call
BB() // BB constructor
B#foo() // plain method call
It's explained very well in the official docs:
https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
So, the Java compiler is adding super() without args for you.
In fact, if the class you are extending doesn't have a default constructor you will be required to call this constructor with args before.
Otherwise, the reason why AA:goo is not being called is because is override by BB even if it doesn't have the #Override annotation, if you want to see that call you need to use super(); in your b:goo method. In fact, the foo is not override because it private so it's not possible to override it, if you try to add the annotation #Override you'll se you have a compilation failure.
AA::foo() is private so AA::foo() and BB::foo() aren't the same.
new BB()
will call AA::Constructor first, calling AA::foo().
AA::foo() call goo() and since you instantiated BB class it'll be BB::goo().
Please use "override" keyword on method when you want to do something like this
There is also a serious design flaw in the example code: it is calling an overridable method from a constructor. This means that object BB might not be fully initialized at the time that this method is called on it. For example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
private Date timestamp;
public BB() {
super();
foo();
timestamp = new Date();
}
public void foo() {
System.out.print("BB:foo ");
}
public void goo() {
// goo() gets called before timestamp is initialized
// causing a NullPointerException
System.out.print("BB::goo " + timestamp.getYear());
}
public static void main(String[] args){
AA obj = new BB();
}
}
Remember this: NEVER CALL AN OVERRIDABLE METHOD FROM A CONSTRUCTOR (even not indirectly as in this example)
Polymorphism is Simple yet Confusing at times when we use different set of names [Which is the case here].
Polymorphism is basically a Parent Child Relationship. Key here is, if you are trying hard to place the names of the classes, use yourself instead i.e. give comment line next to class names as below
public class AA{} //your Parent name
public class BB extends AA{} // yourself i.e. your name
When it comes to the code like this, AA a = new BB(); , decode the code as below:
BB is you, AA is your parent.
new keyword is with YOU(i.e. BB), so a new object of YOU would be created or born. In order to for YOU to born, without your parents(i.e. AA), you cannot exist and so, first they will be born or created (i.e. AA constructor would run). Once your Parents (i.e. AA) are created, then it is time for YOU to born(i.e. BB constructor would run).
In your example,
public AA(){
foo(); -- line A
}
private void foo() {
System.out.print("AA::foo ");
goo(); -- line B
}
public void goo(){
System.out.print("AA::goo "); -- line C
}
As I told earlier, Line A would be called when you say AA a = new BB(); as Line A is in Constructor of AA, Line A calls foo() method and so the control lands in foo(), prints "AA::foo " and executes Line B. Line B calls goo() method and so on it reaches Line C. After Line C is executed, there is nothing left to execute in AA constructor (i.e. Object is created) and so the control flows down to the child Constructor ( As parent is created, it is time for the child to born) and so the child Constructor would be called next.
For Students/Beginners, I strongly recommend to go through Head First Java Edition. It really helps you in laying the Java Foundation Strong.
There something ambiguous about this idea and I need some clarifications.
My problem is when using this code:
public class B {
private void don() {
System.out.println("hoho private");
}
public static void main(String[] args) {
B t = new A();
t.don();
}
}
class A extends B {
public void don() {
System.out.println("hoho public");
}
}
The output is hoho private.
Is this because the main function is in the same class as the method don, or because of overriding?
I have read this idea in a book, and when I put the main function in another class I get a compiler error.
You cannot override a private method. It isn't visible if you cast A to B. You can override a protected method, but that isn't what you're doing here (and yes, here if you move your main to A then you would get the other method. I would recommend the #Override annotation when you intend to override,
class A extends B {
#Override
public void don() { // <-- will not compile if don is private in B.
System.out.println("hoho public");
}
}
In this case why didn't compiler provide an error for using t.don() which is private?
The Java Tutorials: Predefined Annotation Types says (in part)
While it is not required to use this annotation when overriding a method, it helps to prevent errors. If a method marked with #Override fails to correctly override a method in one of its superclasses, the compiler generates an error.
is this because the main function is in the same class as the method "don"
No, it's because A's don() is unrelated to B's don() method, in spite of having the same name and argument list. private methods are hidden inside their class. They cannot be invoked directly by outside callers, such as main method in your case, because they are encapsulated inside the class. They do not participate in method overrides.
No, a private method cannot be overridden since it is not visible from any other class. You have declared a new method for your subclass that has no relation to the superclass method. One way to look at it is to ask yourself whether it would be legal to write super.func() in the Derived class.
You can't override a private method, but you can introduce one in a derived class without a problem. The derive class can not access the private method on the ancestor.
Since t is a on object of type B, calling don() method will invoque the method defined at B. It doesn't even know that there is a method named also don() at class A
private members aren't visible to any other classes, even children
You can't override a private method, but then again, you can't call it either. You can create an identical method with the same name in the child however.
public class A
{
private int calculate() {return 1;}
public void visibleMethod()
{
System.out.println(calculate());
};
}
public class B extends A
{
private int calculate() {return 2;}
public void visibleMethod()
{
System.out.println(calculate());
};
}
If you call A.visibleMethod() it prints out 1.
If you call B.visibleMethod() it prints 2.
If you don't implement the private calculate() method in B, it won't compile because the public method that calls it can't see the private method in A.
(I keep re-reading that question title and thinking about how ridiculous it must look, but I assure you that is the best description of the problem, and I have an actual application where this is the best structure. I swear I'm not crazy.)
Consider the following. Each block is a separate file:
package myPackage;
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
}
}
package myPackage;
import myPackage.A.B;
public class Main {
public static void main(String[] args) {
class C extends B {
public C(A enclosingInstance) {
enclosingInstance.super();
}
public void show() {
System.out.println(A.this.i);
}
}
A myA = new A(2);
C myC = new C(myA);
myC.show();
}
}
Note that the enclosingInstance business is to solve a problem involving intermediate constructor invocations. See "Why can't outer classes extend inner classes?".
I would expect the output to be "2". But instead, I have a compile error on System.out.println(A.this.i);:
No enclosing instance of the type A is accessible in scope
I think the programmatic concept I'm trying to solve is sound: Create a new type of B inside main to give to A that uses things from A that types of B can access.
So what am I doing wrong, or why isn't this possible in java?
EDIT/UPDATE: Note that the same error appears when the code in main is moved to a non-static method. That is to say, I tried moving everything inside of static void main to a new, non-static method of class Main called go(). Then I changed static void main to the single line new Main().go();. The error is in the same spot. So it doesn't seem to be an issue of class C being defined in a static context.
You want A.this to refer to the enclosing instance of the B instance. But why should it? That's not what the syntax means. A.this would mean the enclosing A instance of the C instance, and this does not make sense because C is not an inner class of A.
To make this clearer, here is an example where C is an inner class of A.
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
void foo() {
System.out.println(A.this.i);
}
}
public class C extends B {
C(A a) {
a.super();
}
void bar() {
System.out.println(A.this.i);
}
}
public static void main(String[] args) {
A a1 = new A(1);
A a2 = new A(2);
C c = a1.new C(a2);
c.foo();
c.bar();
}
}
Here C extends B, and both C and B are inner classes of A. Therefore any C has an enclosing A instance, and it also has an enclosing A instance when considered as a B, and these enclosing instances are different (as proved by the fact that foo and bar print different numbers).
So, A.this could not possibly mean what you want it to mean, because it already means something else. I guess the reason why the language designers didn't come up with other syntax to mean the enclosing instance of a super class, is because such syntax would be very complicated, with little pay-off (simple workarounds already exist).
This is absurd code that you should never write for production.
It is, in part, explained in the documentation for Explicit Constructor Invocations
Qualified superclass constructor invocations begin with a Primary
expression or an ExpressionName. They allow a subclass constructor to
explicitly specify the newly created object's immediately enclosing
instance with respect to the direct superclass (§8.1.3). This may be
necessary when the superclass is an inner class.
All this to say that C is a local class (which is an inner class, which is kind of nonsense because if you declare it in a static method there is no enclosing instance) that is a subclass of B but not a nested class of A. As such, there is no enclosing instance. An instance of C does not have an enclosing instance. (Though it would if you declared it in an instance method, but that would be an instance of Main.)
The newly created object's immediately enclosing instance (from JLS) is specified indirectly through a constructor parameter.
You'd have to store it yourself
private A enclosingInstance;
public C(A enclosingInstance) throws CloneNotSupportedException {
enclosingInstance.super();
this.enclosingInstance = enclosingInstance;
}
and since A#i is public, you can access it normally
public void show() {
System.out.println(enclosingInstance.i);
}
With the provided information, I would do this :
public class B {
protected A getOuterInstance() {
return A.this;
}
}
and just let C inherit and use this method. I know you dislike this method but this is the simplest answer I can see. With more information, I would probably propose a design which would try not involving any inner class as this is not a normal use case for inner classes.
Java 8 introduces the concept of default methods. Consider the following interface with a default method :
public interface IDefaultMethod {
public abstract void musImplementThisMethod();
public default void mayOrMayNotImplementThisMethod() {
System.out.println(" This method is optional for classes that implement this interface ");
}
}
And a class that implements this interface :
public class DefaultMethodImpl implements IDefaultMethod {
#Override
public void musImplementThisMethod() {
System.out.println("This method must be implementd ");
}
#Override
public void mayOrMayNotImplementThisMethod() {
// TODO Auto-generated method stub
IDefaultMethod.super.mayOrMayNotImplementThisMethod();
}
}
I have a question about the readability of the following call in the mayOrMayNotImplementThisMethod :
IDefaultMethod.super.mayOrMayNotImplementThisMethod();
I understand that the reason for explicitly specifying the interface name in the above call is to avoid confusion in case multiple interfaces implemented by the class have the same method. What I don't understand is the meaning of the super keyword in this context. When we say IDefaultMethod.super, what exactly are we referring to here? Wouldn't IDefaultMethod.mayOrMayNotImplementThisMethod() be more readable than IDefaultMethod.super.mayOrMayNotImplementThisMethod()? Removing the super keyword makes it more readable at the cost of distinguishing between a static or non static method call.
I will try to contribute to the discussion by following my own reasonings about this.
Using Classes
First, let's see how this work with simple Java classes:
class Barney {
void foo() { System.out.println("Barney says foo"); }
}
class Fred extends Barney {
#Override void foo() { super.foo(); }
}
In this case if we invoke the method foo in a Fred instance it will ask for the implementation of the foo method in its super class and execute that one.
Evidently, none of these others would work:
#Override void foo() { foo(); } //means this.foo() so infinite recursion
#Override void foo() { Barney.foo(); } //means a static method
There is a third configuration that we could do:
class Barney {
void foo() { System.out.println("Barney says foo"); }
class Fred extends Barney {
#Override void foo() { Barney.this.foo(); }
}
}
In this case if we invoke foo in a instance of Fred, since this instance would have a bond with its enclosing instance, this invocation would invoke the foo method in the enclosing instance of Barney.
For instance
new Barney().new Fred().foo();
So, the use of Barney.this here is used to navigate between instances in an inner/outer relation.
Using Interfaces
Now let's try to repeat the same ideas with interfaces.
interface Barney {
default void foo() { System.out.println("Barney says foo"); }
}
interface Fred extends Barney {
#Override default void foo() { Barney.super.foo(); }
}
As far as I can tell, this is exactly the same thing as with classes, it is just that in this case since an interface can inherit from more than one interface we simply qualify the super keyword with the name of the interface we are targeting in this case.
The meaning is the same, we want to invoke the "implementation" of the foo method in the super interface explicitly named.
As with classes, the following would not work:
#Override default void foo() { super.foo(); } //can't be sure of which interface
#Override default void foo() { this.foo(); } //infinite recursion
#Override default void foo() { Barney.foo(); } //static method
#Override default void foo() { Barney.this.foo(); } //not an inner class relation
So, the logical choice here is Interface.super.method().
A question here would be whether we cab ever have a use case like Interface.this.method when using interfaces.
Not really, because interfaces represent a static context, therefore there is never a concept like that of inner classes between interfaces. So this is never possible.
interface Barney {
default void foo() { System.out.println("Barney says foo"); }
interface Fred extends Barney {
#Override default void foo() { Barney.this.foo(); }
}
}
Basically, this is not possible because the code above does not mean that an instance of Fred would need to exist within the context of an instance of Barney. This is just a static inner interface and instances of it can exist independently of any instances of the parent interface.
So, that's why this would not be a good choice.
So, as you can see, after all this the use of super kind of makes sense, or at least I hope I have explained myself well enough to convey that idea.
This is simply an extension to default methods of the usual approach to accessing members of superclasses (JLS 15.11):
The form T.super.Identifier refers to the field named Identifier of the lexically enclosing instance corresponding to T, but with that instance viewed as an instance of the superclass of T.
Essentially, there can be ambiguity about which member is being referred to when a class has more than one ancestor (whether because of default methods or just because it has multiple superclasses in a hierarchy). The super keyword is the analog of Outer.this in an inner class; it means that you want to get "this, but the stuff I would see inside the body of that superclass instead of the member inside this subclass".
super refers to a class or interface you inherit from. It is means you want to call a method ignoring the fact it has been overridden.
If you used this you would be referring to this class (or a sub-class) and thus have infinite recursion.
Java 8 interfaces also have static methods.
If you say,
IDefaultMethod.mayOrMayNotImplementThisMethod();
Then it is a way to call static method, which also seems correct as it is similar to how we access static members of class.
For default method, if 'super' is not used then they might have used 'this', which does not make sense as 'this' belongs to class where we are making method call.
My opinion is, you are correct as it does not provide good readability but seems it is as per language design.