Why doesn't Java automatically access the overridden method? - java

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.

Related

Is this Dynamic polymorphism or not?

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

Why does this.getClass give it's own class name rather than Anonymous class name?

I have created anonymous class by implementing interface I inside public static void main() method. So, by java 8 for the abstract method test(), the implementation is provided from imple() method of class C.
So, inside public static void main() method, printing _interface.getClass(), I got
package_path.Main$$Lambda$1/310656974 which is absolutely fine. Bacause it print's the anonymous class name.
Also, _interface is pointing to an anonymous object in heap and hence I'm doing _interface.test();
So, the first statement that test() method has now is to print the class name,
But eventually what it print was,
package_path.C (telling me C is the class name). How is that possible? Shouldn't package_path.Main$$Lambda$1/310656974 be printed again? Because 'this' means anonymous inside the test method right?
#java.lang.FunctionalInterface
interface I {
void test();
}
class C {
void imple() {
System.out.println(this.getClass());
System.out.println("Inside Implementation");
}
}
class Main {
public static void main(String[] args) {
I _interface = new C()::imple;
System.out.println(_interface.getClass());
_interface.test();
}
}
Hopefully, this might help you understand, that when you declare
I _interface = new C()::imple;
you've actually implemented the interface somewhat similar to (though not same as):
I _interface = new I() {
#Override
public void test() {
new C().imple(); // creating an instance of class `C` and calling its 'imple' method
}
};
Hence when the test method is called, it first creates an instance of C which prints
class x.y.z.C
as the class.
Because 'this' means anonymous inside the test method right?
Now as you can see above, there is no more anonymous class from which imple
is being called from, hence this is not representing the anonymous class anymore.
As Holger clarified in comments further, despite the representation as lambda or anonymous class at the calling site, the this.getClass() inside a method of class C will evaluate to C.class, regardless of how the caller looks like.
Recommend: Continue to read and follow on Is there any runtime benefit of using lambda expression in Java?

Can't seem to understand complex polymorphism

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.

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 Exception or Error not generated when no main method found?

Ok just for sake knowledge , I tried below cases (Assume that Class A and B are in same package)
ClassA
public class ClassA {
public static void main(String[] args) {
System.out.println("A");
}
}
ClassB
public class ClassB extends ClassA {
public static void main(String[] args) {
System.out.println("B");
}
}
executing above ClassB it will produce output of B now after below change in classB
ClassB
public class ClassB extends ClassA {
//blank body
}
If I compile and run in terminal it gives me output A that was totally surprising as it should had given NoSuchMethodError as no main method was their so kindly explain the weird behavior ?
Note: Many answers contains Override word please use hiding as we cannot override static methods in java.
In the first case, you're hiding the main method since you're defining a new one in the subclass, in the second case you didn't you'll inherent A's main.
See The Java™ Tutorials - Overriding and Hiding:
If a subclass defines a static method with the same signature as a
static method in the superclass, then the method in the subclass hides the one in the superclass.
In Java subclasses inherit all methods of their base classes, including their static methods.
Defining an instance method in the subclass with the matching name and parameters of a method in the superclass is an override. Doing the same thing for static methods hides the method of the superclass.
Hiding does not mean that the method disappears, though: both methods remain callable with the appropriate syntax. In your first example everything is clear: both A and B have their own main; calling A.main() prints A, while calling B.main() prints B.
In your second example, calling B.main() is also allowed. Since main is inherited from A, the result is printing A.
public static void main(String[] args) is just a method which you inherit from A in second case.

Categories