I am looking for a way to explain how the following Java program should be traced (which method is called, etc), esp how the access modifier & inheritance affects the method invocation.
I have two classes A and B, where B extends A.
Class A has private method process()
Class B has public method process()
Class A has public method callProcess() which calls process().
In the main program, I create an object B and call method callProcess().
class A {
private void process(){
System.out.println("Process A.");
}
public void callProcess(){
process();
}
}
class B extends A {
public void process(){
System.out.println("Process B.");
}
}
class MethodTest{
public static void main(String[] args){
B b1 = new B();
b1.callProcess();
}
}
I expect that the process() from B is invoked since the object that calls process() is of type B, but what happens is process() from A is invoked.
What's weirder is if I change the modifier of process() in A to public then the process() in B is invoked.
Since process from A is a private method, B is completely unaware of its existence and it cannot be overridden.
Similarly, when you call callProcess on an instance of B, it calls A.callProcess (since it was not overridden in B). A only knows of its own process method (which cannot be overridden) and calls that.
If you were to change the visibility of the process method in A to be either public or protected, then it can be overridden in B, as long as the signature matches i.e. they must have the same visibility.
Yes, for the override to be implicit, the overrided method cannot have a more restrictive access level than the overriding one.
Related
Let's say I have two classes, a and b.
public class a{
public void m1(){
System.out.println("a1");
}
public void m2(){
m1(); //overridden in b
System.out.println("a2");
}
}
public class b extends a{
public static void main(String[] args){
b obj = new b();
obj.m2();
}
public void m1(){
System.out.println("b1");
}
}
I'm curious to know if there's a way to force a's m2() to always call a's m1(), rather than b's or any other subclass's. I realize that super.m1() will call a's m1() if overridden by b, but my concern is that this means m1() must be overridden in every subclass, and the superclass itself could not call m2(). I would like every call to a's m2() to call a's m1() inside of itself, regardless of whether or not it is called in a, a subclass like b that has overridden m1(), or a subclass that has not overwritten m1().
I have found some mention here of using reflection to do things like this, but it sounds like these approaches are expensive. Is there another, preferably cheaper way?
Given the following source and ouput:
Source:
public class A
{
public void foo()
{
bar();
}
public void bar()
{
System.out.println ("in A's bar() method");
}
}
public class B extends A
{
#Override
public void foo()
{
super.foo();
// Do some specialized B stuff
}
#Override
public void bar()
{
System.out.println ("in B's bar() method");
}
}
public class Main
{
public static void main (String... args)
{
B b = new B();
b.foo();
}
}
Output:
in B's bar() method
Can someone please explain to me how the JVM is smart enough to polymorphically call B's (as opposed to A's) bar() method in this situation? I'd like to know what kind of dynamic dispatch magic is going on behind the scenes here.
Update: In case I wasn't clear enough, I know basically WHAT is happening, I'm looking for specific details on HOW the JVM makes it happen under the hood. The answers so far are too simplistic.
Update 2: Maybe I wasn't clear enough. When b.foo() is called, then super.foo() is called, then bar() is called in class A's foo(). How does the bar() that is called when specifically invoking super.foo() not call class A's bar() method, since the super keyword explicitly specifies class A? What steps does the JVM have to go through to sort this out?
Also, does this mean it's a bad idea in general to call public methods from within their own class since they can be overridden in this way?
Java uses the object's type when invoking the methods.
A b = new B();
b.foo();
Let's say you used above code.
Here what will happen is you are creating an object of type B and assign it to a reference of type A. Since the object type is B, you'll invoke the method in class B.
Even if the constructor or method you're currently in is defined in a super-class, the object doesn't change type. It will still be an object of type B. This can be demonstrated by using the this keyword.
this refers to the current object. That is not the same as the class defining the current method or constructor.
Try typing the following into A's constructor or in the foo() method:
System.out.println(this.getClass());
The function call sequence is (from eclipse debug view):
1. B.foo() // super.foo()
2. B(A).foo() // bar()
3. B.bar()
After the thread calls super.foo(), the JVM will check if there's any implementation in B (since we still hold B.class in the stack), if there is, JVM will call it.
This feature is guaranteed by JVM implementation. It is not smart, it just be designed this way, just like C++'s virtual methods.
Hope it helps.
I know that we cannot override static methods in Java, but can someone explain the following code?
class A {
public static void a() {
System.out.println("A.a()");
}
}
class B extends A {
public static void a() {
System.out.println("B.a()");
}
}
How was I able to override method a() in class B?
You didn't override anything here. To see for yourself, Try putting #Override annotation before public static void a() in class B and Java will throw an error.
You just defined a function in class B called a(), which is distinct (no relation whatsoever) from the function a() in class A.
But Because B.a() has the same name as a function in the parent class, it hides A.a() [As pointed by Eng. Fouad]. At runtime, the compiler uses the actual class of the declared reference to determine which method to run. For example,
B b = new B();
b.a() //prints B.a()
A a = (A)b;
a.a() //print A.a(). Uses the declared reference's class to find the method.
You cannot override static methods in Java. Remember static methods and fields are associated with the class, not with the objects. (Although, in some languages like Smalltalk, this is possible).
I found some good answers here: Why doesn't Java allow overriding of static methods?
That's called hiding a method, as stated in the Java tutorial Overriding and Hiding Methods:
If a subclass defines a class method with the same signature as a
class method in the superclass, the method in the subclass hides the
one in the superclass.
static methods are not inherited so its B's separate copy of method
static are related to class not the state of Object
You didn't override the method a(), because static methods are not inherited. If you had put #Override, you would have seen an error.
A.java:10: error: method does not override or implement a method from a supertype
#Override
^
1 error
But that doesn't stop you from defining static methods with the same signature in both classes.
Also, the choice of method to call depends on the declared type of the variable.
B b = null;
b.a(); // (1) prints B.a()
A a = new B();
a.a(); // (2) prints a.a()
At (1), if the system cared about the identity of b, it would throw a NPE. and at (2), the value of a is ignored. Since a is declared as an A, A.a() is called.
Your method is not overridden method. you just try to put #Override annotation before your method in derived class. it will give you a compile time error. so java will not allow you to override static method.
While goblinjuice answer was accepted, I thought the example code could improved:
public class StaticTest {
public static void main(String[] args) {
A.print();
B.print();
System.out.println("-");
A a = new A();
B b = new B();
a.print();
b.print();
System.out.println("-");
A c = b;
c.print();
}
}
class A {
public static void print() {
System.out.println("A");
}
}
class B extends A {
public static void print() {
System.out.println("B");
}
}
Produces:
A
B
-
A
B
-
A
If B had overridden print() it would have write B on the final line.
Static methods will called by its Class name so we don't need to create class object we just cal it with class name so we can't override static
for example
class AClass{
public static void test(){
}
}
class BClass extends AClass{
public static void test(){}
}
class CClass extends BClass{
public static void main(String args[]){
AClass aclass=new AClass();
aclass.test(); // its wrong because static method is called
// by its class name it can't accept object
}
}
we just call it
AClass.test();
means static class can't be overridden
if it's overridden then how to cal it .
Static members belong to class not to any objects. Therefore static methods cannot be overriden. Also overiding happens at run time therefore compiler will not complain.
Howeve, you can add #Override annotation to method. This will flag compiler error.
abstract class A {
public void methodA() {
System.out.println("methodA");
methodB();
showName();
}
public abstract void methodB();
public void showName() {
System.out.println("in showname base");
}
}
class B extends A {
public void methodB() {
System.out.println("methodB");
}
public void showName() {
System.out.println("in showname child");
}
}
public class SampleClass {
public static void main(String[] args) {
A a = new B();
a.methodA();
}
}
Output is :
methodA
methodB
in showname child
Question :-
Since in overriding, the object type is considered. Is it the reason behind that class B's showName() method called not of class A's? If not then whats the cause of this output order?
You created an object of type B, so all methods called on that object will be on class B. If class B does not implement some methods (like methodA), then Java tries to find a method in the parent class (A). You should read about polymorphism in object oriented languages:
http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming
It's easy:
A a = new B();
a.methodA();
here is known that a is object of B class, so every method that can be overriden in class B is used from class B if there is no overriding, then method from class A must be used.
Considering order:
you invoke methodA that is declared as:
public void methodA() {
System.out.println("methodA");
methodB();
showName();
}
from inside of methodA() you invoke both methodB() and showName(). They are overriden in class B, and object a is instanceof B, so that's why they (from B class) are used.
EDIT as mentioned in comment:
#Jaikrat Singh, class B is still class A (child of it, but inheritance is relation of type: IS-A ). Class B has inherited methods from A class. So it has methodA as well. So it's better to say, that methodA is also called from class B but with is default code - the same as provided in class A
While the object 'a' is declared as type A, it is instantiated as type B. Polymorphism causes the methods of the instance type to be called rather than those of the declaration type, so because it is internally of type B, the showName() method of class B is called.
When you call a.methodA(), since your object type is B, it will look for methodA first in B. Since there is no such method in B, it will look for this method in its super class, which is A. Finding methodA in class A, it will start to execute.
Executing, it will print methodA and start looking for the next called method (methodB), which is implemented in the B class, then it will print methodB.
The next called method is showName, which is implemented in both classes. Since Java will start looking for the implementation in the same class as the object type, it will find in its first attempt, which is class B.
The main rule is simple: Java will first try to find the method in the object type class (the name that goes after the new operator). If the method is not implemented there, it will start to go up through the super classes.
You have the abstract class A, and it is extended by B. Extends is equivalent to B "is a" A. For example if apple extended fruit, apple 'is a' fruit. It acts like a fruit but also does apple things that a banana wouldn't do. So B acts the same way as A, but then also can do other stuff. So in your example, your B overwrites two methods. They will be called by every B object by default. In order to access A's methods from a B, you need to use the keyword super .
It is part of polymorphism (a key point in java programming) that an object will find any methods in itself first (even if they are overwritten from a parent) and then it will climb the tree of inheritance to find a method that isn't directly in that class.
For your example:
public void methodA() {
System.out.println("methodA"); //This prints no problem.
methodB(); //This searches the "B" class for a method called "methodB" If it can't find it, it checks its parent for a "methodB"
showName();//This searches the "B" class for a method called "showName" If it can't find it, it checks its parent for a "showName"
}
The above code gets called. You know this much (from other comments you made, I'm assuming this.) Once the line methodB() gets called, your object of type B checks the entire B file for the method. It would only jump up to A for the method if it didn't exist. Then it would do the same for showName().
I have a super class:
public class SuperClass {
public void dosomething() {
firstMethod();
secondMethod();
}
public void firstMethod() {
System.out.println("Super first method");
}
public void secondMethod() {
System.out.println("Super second method");
}
}
A sub class:
public class SubClass extends SuperClass {
public void dosomething() {
super.dosomething();
}
public void firstMethod() {
System.out.println("Sub first method");
}
public void secondMethod() {
System.out.println("Sub second method");
}
}
A test class:
public static void main(String[] args) {
SubClass sub = new SubClass();
sub.dosomething();
SuperClass sup = new SuperClass();
sup.dosomething()
}
when I run the test method, I got this:
Sub first method
Sub second method
Can you tell me how this happened? In the sub class dosomething method, I called super.dosomething() and I think the super method will be called, but the override method in sub class was called.
if I do this:
SuperClass superClass = new SuperClass();
superClass.dosomething();
the result is:
Super first method
Super second method
The difference is method invocation place. I think there must be something I don`t know ):
oops!the super reference pointed to subclass in the first example...
like this:
SuperClass sub = new SubClass();
sub.firstMethod();
sub.secondMethod();
In java, the methods binding is always dynamic [ignoring static and private methods here]. Thus, when you override firstMethod() and secondMethod(), any time an object of type SubClass will try to invoke one of them - the overriden method will be invoked - even if it [the invokation] is from the parent's method.
So, as expected - when you invoke super.doSomething(), it calls firstMethod() and secondMethod(), and the overriden methods are being called.
Your object on which the methods are invoked is of type SubClass, not SuperClass. Even if you call a method that is only defined in SuperClass, your execution context remains SubClass. So any method that is invoked that is overridden will in fact execute the overridden method.
The thing to take away from this is that by declaring firstMethod and secondMethod as public, SuperClass is in fact allowing subclasses to override their behaviour. If this is not appropriate, the methods should be private, or final.
Indeed the super doSomething gets called. Do something calls firstMethod and secondMethod, which are virtual methods (any method in Java is by default virtual, which means it can be overriden). So their overriden versions gets called.
You can prevent them from being overriden if you mark them final.
Super.dosomething() does in fact call the method dosomething() in Super class. But inside this method, you call 2 functions which are firstMethod and secondMethod. These methods are overwritten in the Sub class and they are being called from the Sub Class.
As Petar Ivanov suggested:
You can prevent them from being overriden if you mark them final