Is this Dynamic polymorphism or not? - java

The output of the program is A isn't it suppose to be B. If I change the modifier of method in Class A to public then the output is B. Can somebody explain what is going on here?
Code:
public class HelloWorld {
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.createInstance();
}
public void createInstance() {
A b = new B();
b.isTrue();
}
public class A {
private void isTrue() {
System.out.println("A");
}
}
public class B extends A {
public void isTrue() {
System.out.println("B");
}
}
}
Output: A

If isTrue() in A was public, then isTrue() in B would override it. (Overriding means if you call a method declared in the base class, the matching method in the subclass is executed.)
In this case, since isTrue() in A is private, the two isTrue() methods are independent. Private methods are not subject to overriding.
Since you are calling isTrue() on a variable of type A, it is the isTrue() method in A that is executed. Being private does not, in this case, prevent you accessing the method, because all your code is inside one class, HelloWorld. If your classes were not inner (or nested) classes, then you wouldn't be able to call the private method from outside the class it is declared in.

You are creating a B instance, pointed by an A Instance.
As A isTrue is private, the compiler will raise an error
If you make A.isTrue() public, as you created a B instance it will execute B isTrue method, as that method is overridden
Due your classes are inner classes, when you call isTrue pointed by A class it executes isTrue from A and does not apply the override because the methods have different visibility. When you make isTrue from A public it applies polymorphism as they have the same modifier.
The confussion is because they are inner classes, if they weren't inner classes your code won't compile

Related

Why doesn't Java automatically access the overridden method?

Given two classes, a parent class and a child class:
class A {
private void greet() {
System.out.println("Class A");
}
}
class B extends A {
public void greet() {
System.out.println("Class B");
}
}
One has a method called greet(), which is private, and the other one defines a method with the same name, only that it is public. Now, as far as I know, the child's greet() method doesn't override the parent's method, because it 'hides' it? (given the fact that private methods can't be overridden?)
Now, given the following class and method (considered to be in the same package as A and B):
public class Main {
public static void main(String[] args) {
B b = new B();
b.greet();
}
}
This should compile. But this one:
public class Main {
public static void main(String[] args) {
A a = new B();
b.greet();
}
}
This one up here doesn't compile, because it's missing a typecast.
My question would be: why? If the greet() method was public in both places, it would have shown Class B both times. I'm pretty confused about why Java doesn't figure at runtime, for the second case, that a is actually referencing to an object of type B, and directly calls the method from class B.
Tried reading more about polymorphism in an OCA-preparation book, but the authors didn't seem to be so specific about it.
In your snippet that doesn't compile, the compiler sees that the compile time type of a is class A.
Therefore, it will only allow you to call accessible methods of class A (or of super-classes of A). greet is a private method of A, and therefore not accessible. Therefore the compiler doesn't allow calling it.
The fact that the runtime type of a would be class B, which has an accessible greet method, makes no difference, since the compiler doesn't try to figure out what the runtime type of a variable would be.
At compile time A.greet() is not accessible.
Hence does not compile.
For overriding, the method must be accessible at compile time, but the decision to call the method is done at runtime.

Java Inheritance: How to invoke super class method when subclass instance is created?

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() {}
}

Override "private" method in java

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.

Why can't a local class that extends an inner class access the inner class enclosing instance?

(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.

Anonymous class, Inheritance, and overriding

public class A {
public A() {
foo();
}
private void foo() {
System.out.print("A::foo ");
goo();
}
public void goo() {
System.out.print("A::goo ");
}
}
public class B extends A {
public B() {
foo();
}
public void foo() {
System.out.print("B::foo ");
}
public void goo() {
System.out.print("B::goo ");
}
public static void main(String[] args) {
A b = new B() {
public void foo() {System.out.print("Anonymous::foo ");}
public void goo() {((B)this).foo();}
};
}
}
I'd like your help with understanding why does the program print A::foo Anonymous::foo Anonymous::foo. Is this anonymous class replace the former B? overrides its methods?
As I see it, it should go to A's default constructor, run A's foo- print "A::foo", than run B's goo, since it was properly overrided, but now B's goo is the one in the Anonymous class, so it casts this to B (Which does nothing), and run its foo, which is the foo above, of B, so it should print "Anonymous:foo". What do I get wrong?
Thanks a lot.
Your question isn't all that clear, but let me just say that the the answer would be exactly the same if instead of an anonymous class extending B, you had a top-level class C extending B. Nothing about anonymous classes makes them behave differently with respect to polymorphism and inheritance. When B's constructor calls foo(), the overriding version in the most-derived class -- here the anonymous class -- is invoked.
I think the confusing thing here is you have two foo methods. One is private so it's not eligible for overriding, the other is public so it can be overridden. B is calling foo in its constructor but that's overridden by its subclass.
A's constuctor calls A.foo (A::foo) because it is private and so not overloaded. A.foo calls goo() which was overridden by B and then by Anonymous so you get Anonymous.goo -> Anonymous.foo (Anonymous::foo). Then B's constructor calls foo which is overridden by Anonymous so (Anonymous::foo)
Using that kind of anonymous construction in fact creates a subclass of B. You have overridden B's methods with the ones you provide in the anonymous class so those will be used instead.

Categories