Java Dispatching-Runtime type - java

I am confused with method dispatching in java. Why does the first method "a.m1(b)" call to the class A?
The calling variable is a. And its runtime type is B, isn't it?
class A {
public void m1(A a){
System.out.println("A-m1");
}
public void m1(){
System.out.println("A-m1");
}
}
class B extends A {
public void m1( B b){
System.out.println("B-m1");
}
public void m1(){
System.out.println("B-m1");
}
}
public class HelloWorld {
public static void main(String[] args) {
B b = new B();
A a = new B();
a.m1(b);//prints A-m1
a.m1();//prints B-m1
}
}

Overload resolution is done based on compile-time types. A variable of type A only exposes the methods m1() and m1(A). Because you pass in a parameter, m1(A) is invoked; or rather, the appropriate override thereof. Except that m1(B) is not an override of m1(A). (Off the top of my head, I don't know if overrides can widen argument signatures, but they certainly can't narrow them.)

Related

Question about overwritten methods in classes that extend each other.

I'm studying for a Java-exam and have a question concerning static and dynamic types.
I've got 4 classes: A, B, C and Main.
public class A {
private void tell(){
System.out.println("AA");
}
}
public class B extends A {
public void tell(){
System.out.println("BB");
}
}
public class C extends B {
}
public class Main{
public static void main(String[] args) {
A c = new C();
c.tell();
}
}
My suggestion was: the output should be "BB", because c has the dynamic type C. Since C doesn't have the method "tell" the method of the upper class B is used, which prints "BB".
The outcome however is an error, because Java looks for "tell" in A. In A it of course can't find it, because there it is declared priavte. But why does it look in A, although only it's static type is A, but it's dynamic type is C?
You are getting an error because at compile time, the compiler does not know the actual instance that will be put in A, so when the compiler sees c.tell() he only looks at the class A which indeed does not have an acessible tell() method.
One way to understand this is with this example:
public class A {
private void tell(){
System.out.println("AA");
}
}
public class B extends A {
public void tell(){
System.out.println("BB");
}
}
public class C extends A {
}
public class Main{
public static void main(String[] args) {
A b = new B();
b.tell();
A c = new C();
c.tell();
}
}
You can see that the first 2 lines would be ok (by your current logic of thinking). B has the method tell() so b should be able to call tell(). But using the exact same assignment with another subclass of C which does not have the tell() method then your logic would fail. A nor C have the tell() method so the program suddenly has a call to a method that does not exist or is not accessible.

Instantiating base class using derived class?

Here is my code, I cannot reason out why the output is coming to be like that. If anyone can explain please.
import java.io.*;
class b {
void m(b a){
System.out.println(" b");
}
}
class bcd extends b {
void m(bcd a){
System.out.println("bcd");
}
}
class cde extends bcd {
void m(cde a){
System.out.println("cde");
}
}
public class ABC{
public static void main(String[] args){
b ob1= new cde();
cde ob2=new cde();
ob1.m(ob2);
}
}
In your example will call method in class b. I think you want to show overriding or overloading example, but this is not overriding and not overloading.
For overriding use late binding. In this case, knowing the method signature, the virtual machine analyzes instantiating(real) type of object on which this method is called to determine exactly which class to take the definition of the method being called.
For overloading use earlier binding. In this case, compiler checking a formal type of object
Good example explain overriding or overloading this:
public class Test{
public static class Parent{
public void test(){
System.out.println("parent class");
}
}
public static class Child extends Parent{
public void test(){
System.out.println("child class");
}
}
public static class Tester{
public void test(Parent obj){
System.out.println("Parent method");
obj.test();
}
public void test(Child obj){
System.out.println("Child method");
obj.test();
}
}
public static void main(String[] args){
Parent obj = new Child();
Tester t = new Tester();
t.test(obj);
}
}
Result execution:
Parent method
child class
EDIT:
1)Compiler don't look on type the parameter. It determine, what method calling, based on real type object on which it was called: for your example this is b class, for my example this is Tester class.2) if we have two methods in a class with the same name, but different type parameter in the method (overloading), then java virtual machine look on the type parameter(how in my example: two methods with the same name, but transmitted the object of class Parent and calling method with Parent parameter)
In your example if was like this:
class B {
void m(B a){
System.out.println(" b");
}
void m(Cde a){
System.out.println("cde");
}
}
public class ABC{
public static void main(String[] args){
B ob1= new Cde();
Cde ob2=new Cde();
ob1.m(ob2);
}
}
It's example overloading and will call void m(cde a)
EDIT2:
Yes, your ob1 object is instance cde, but java virtual machine check instantiating(real) type of object only in case overriding(when signature of methods in two classes are identical). So, you need to remember two things overriding and overloading, in other cases compiler look on formal type reference, in your example this is b.
But there is interesting thing with overriding.
From http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.5
Return types may vary among methods that override each other if the
return types are reference types. The notion of
return-type-substitutability supports covariant returns, that is, the
specialization of the return type to a subtype.
A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2,
if and only if the following conditions hold:
If R1 is void then R2 is void.
If R1 is a primitive type, then R2 is identical to R1.
If R1 is a reference type then:
R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (ยง5.1.9), or
R1 = |R2|
if you have this code with different return type, but identical parameter, it will be example overriding too:
class Bcd extends B {
#Override
Bcd m(Cde a) {
System.out.println("bcd");
return a;
}
}
class Cde extends Bcd {
#Override
Cde m(Cde a) {
System.out.println("cde");
return a;
}
}
class B {
B m(Cde a) {
System.out.println("b");
return a;
}
}
class Test {
public static void main(String[] args) {
final B ob1 = new Cde();
final Cde ob2 = new Cde();
ob1.m(ob2);
}
}
Result:
cde
Because this is overriding too.
When you are calling ob1.m(ob2); then method of class b is getting invoked.
The methods defined in class
class bcd extends b {
void m(bcd a) {
System.out.println("bcd");
}
}
class cde extends bcd {
void m(cde a) {
System.out.println("cde");
}
}
are overloaded methods not overriden methods.

Java - Subclass calls supers constructor which calls subclass method instead of its own

I'll start with a code example:
class A {
public A() {
f(); //When accessed through super() call this does not call A.f() as I had expected.
}
public void f() {} //I expect this to be called from the constructor.
}
class B extends A {
private Object o;
public B() {
super();
o = new Object(); //Note, created after super() call.
}
#Override
public void f() {
//Anything that access o.
o.hashCode(); //Throws NullPointerException.
super.f();
}
}
public class Init {
public static void main(String[] args) {
B b = new B();
}
}
This program throws a NullPointerException. When the object b enters the constructor of its superclass A and makes a call to the method f() which is overridden by the class B B.f() is called, instead of A.f() which I would have expected.
I thought a superclass wasn't supposed to know if it was subclassed or not but surely this can be used by a class to tell if it's been subclassed or not? What's the reason behind this? Is there any workaround if I really want A.f() to be called instead of B.f()?
Thanks in advance.
Follow up question:
Thanks for the answers. I now understand why it is like it is, but here's a follow up question. Perhaps I'm mistaken but a principle of subtyping is that the supertype should not know that it's been subtyped. This "mechanism" lets a class know if it's been subclassed or not. Consider this code example:
class A {
private boolean isSubclassed = true;
public A() {
f(); //A.f() unsets the isSubclassed flag, B.f() does not.
if(this.isSubclassed) {
System.out.println("I'm subclassed.");
} else {
System.out.println("I'm not subclassed.");
}
}
public void f() {
this.isSubclassed = false;
}
}
class B extends A {
public B() {
super();
}
#Override
public void f() {}
}
public class Init {
public static void main(String[] args) {
new B(); //Subclass.
new A();
}
}
The output of this program is:
I'm subclassed.
I'm not subclassed.
Here A knows it's been subclassed. It's unkown by whom but that doesn't matter. How is this explained? Am I misinformed?
The NullPointerException occurs because when you construct an instance of B, the parent constructor (in A) is invoked. This constructor calls the f() method but since the actual type of the object is B, the overridden f() method in B is invoked.
#Override
public void f() {
//Anything that access o.
o.hashCode(); //Throws NullPointerException as o has not been initialised yet
super.f();
}
The lesson here is never to call a method in a constructor which can be overridden by a subclass.
This is why you shouldn't call non-private methods from constructors. There is no workaround, except making the method private.
This is the reason that override hide the own method. At the call of f() at super class constructor, it hide super class method call. Actually it is call to subclass overided method.
class A{
public A() {
f(); // It call the subclass overided method.
}
// This method is hide due to override.
public void f() {
}
}
class B extends A {
// This method is called before constructor where Object o is Null, hence you
// got NullPointerExcetion.
#Override
public void f() {
// Anything that access o.
o.hashCode(); // Throws NullPointerException.
super.f();
}
}
class A {
public A() {
System.out.println(1);
f();
// where super(),this will be called by subclass ,but subclass's o is null
}
public void f() {
System.out.println(4);
}
}

Explicitly calling a default method in Java

Java 8 introduces default methods to provide the ability to extend interfaces without the need to modify existing implementations.
I wonder if it's possible to explicitly invoke the default implementation of a method when that method has been overridden or is not available because of conflicting default implementations in different interfaces.
interface A {
default void foo() {
System.out.println("A.foo");
}
}
class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
// how to invoke A.foo() here?
}
}
Considering the code above, how would you call A.foo() from a method of class B?
As per this article you access default method in interface A using
A.super.foo();
This could be used as follows (assuming interfaces A and C both have default methods foo())
public class ChildClass implements A, C {
#Override
public void foo() {
//you could completely override the default implementations
doSomethingElse();
//or manage conflicts between the same method foo() in both A and C
A.super.foo();
}
public void bah() {
A.super.foo(); //original foo() from A accessed
C.super.foo(); //original foo() from C accessed
}
}
A and C can both have .foo() methods and the specific default implementation can be chosen or you can use one (or both) as part of your new foo() method. You can also use the same syntax to access the default versions in other methods in your implementing class.
Formal description of the method invocation syntax can be found in the chapter 15 of the JLS.
This answer is written mainly for users who are coming from question 45047550 which is closed.
Java 8 interfaces introduce some aspects of multiple inheritance. Default methods have an implemented function body. To call a method from the super class you can use the keyword super, but if you want to make this with a super interface it's required to name it explicitly.
class ParentClass {
public void hello() {
System.out.println("Hello ParentClass!");
}
}
interface InterfaceFoo {
public default void hello() {
System.out.println("Hello InterfaceFoo!");
}
}
interface InterfaceBar {
public default void hello() {
System.out.println("Hello InterfaceBar!");
}
}
public class Example extends ParentClass implements InterfaceFoo, InterfaceBar {
public void hello() {
super.hello(); // (note: ParentClass.super could not be used)
InterfaceFoo.super.hello();
InterfaceBar.super.hello();
}
public static void main(String[] args) {
new Example().hello();
}
}
Output:
Hello ParentClass!
Hello InterfaceFoo!
Hello InterfaceBar!
The code below should work.
public class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
void aFoo() {
A.super.foo();
}
public static void main(String[] args) {
B b = new B();
b.foo();
b.aFoo();
}
}
interface A {
default void foo() {
System.out.println("A.foo");
}
}
Output:
B.foo
A.foo
You don't need to override the default method of an interface. Just call it like the following:
public class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
A.super.foo();
}
public static void main(String[] args) {
B b=new B();
b.afoo();
}
}
Output:
A.foo
It depends on your choice whether you want to override the default method of an interface or not. Because default are similar to instance method of a class which can be directly called upon the implementing class object. (In short default method of an interface is inherited by implementing class)
Consider the following example:
interface I{
default void print(){
System.out.println("Interface");
}
}
abstract class Abs{
public void print(){
System.out.println("Abstract");
}
}
public class Test extends Abs implements I{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
Test t = new Test();
t.print();// calls Abstract's print method and How to call interface's defaut method?
}
}

Why does my child class not initialize variables properly in java

In the code below, myString is always initialized to null. I have to manually initialize in an init() or similar. As far as I can tell it is related to superclass/subclass but I don't understand the exact mechanism
public class A extends B {
private String myString = "test";
public static void main(String[] args) {
new A();
}
public A() {
super();
}
public void c() {
System.out.println(myString);
}
}
public class B {
public B() {
c();
}
public void c() {
}
}
The issue with your code is, that myString is initialized at the begin of the constructor of class A but right after the super constructor (i.e. class B). Since you access the variable before from the constructor of class B (indirectly via call to overriden methode c) your get this behaviour.
As a rule of thumb: if you want to avoid unexpected behavior do not call overriden methods before the constructor has been executed.
Add a call to c(); overidden method right after the object has been fully created and call to superclass constructor is done.
Change your code to this ..
public class A extends B {
private String myString = "test";
public static void main(String[] args) {
new A();
}
public A() {
super();
c(); // Include the call to c(); here ...
}
public void c() {
System.out.println(myString);
}
}
public class B {
public B() {
}
public void c() {
}
}
// Output : test
Thinking in Java Second Edition by Bruce Eckel, Behavior of polymorphic methods
inside constructors (p. 337-339).

Categories

Resources