Laura
Laura

Reputation: 163

Java: Overloading methods

I am wondering why the call of

z.f(-6);

in class M refers to the following function in class B:

public void f(double y) {
    this.x = (int) y + B.y;
}

instead of using function f in class A, since b.x is covered by A. Or rather uses

public void f (int y) {
    this.x = y*2;
    B.y = this.x;
}

in class B where at least the parameter type matches.

Complete Code below:

public class A {
    public int x = 1;
    public A(int x) {
        this.x += x;
    }
     public A (double x) {
        x += x;
    }
    public void f(double x) {
        this.x = this.x + (int) (x + B.y);
    }
}

public class B extends A {
    public static int y = 3;
    public int x = 0;
    public B (double x) {
        super((int) x);
    }
    public void f(int y) {
        this.x = y*2;
        B.y = this.x;
    }
    public void f(double y) {
        this.x = (int) y + B.y;
    }
  }

public class M {
      public static void main (String[] args){
        A a = new A(B.y);
        a.f(1);
        B b = new B(3.0);
        A z = b;
        z.f(-5.0);
        z.f(-6);
        System.out.println(b.x + "   " + z.x);
       }
  }

Upvotes: 4

Views: 438

Answers (4)

Trevor Freeman
Trevor Freeman

Reputation: 7232

Java is single dispatch, whereas what you are attempting to do is double dispatch (where the method invoked depends on both the dynamic runtime class and parameters).

The signature of a method to invoke in Java is determined at compile time; this means that the declared class of the object determines which method is bound to. Overriding a method in a subclass affects the bound implementation, but overloading a method does not (since the overloaded method has a different signature).

In class B you are overloading f() with a version that takes an int, when using an object declared as being of class A, this method does not appear to exist (you cannot call it, and it will not be invoked).

To summarize:

  • The compiler binds to a method signature at compile time.
  • This bound signature depends on the declared (compile time) type of the object and parameters.
  • If a method is overridden in a subclass, then when invoking on the subclass (regardless of the declared type), the overridden method will be chosen.
  • Overloading is not overriding, to override you need the same method signature (well, excepting covariance).

Upvotes: 1

carlos.perezb
carlos.perezb

Reputation: 53

Well I might be wrong, but if you link the object z of type A to an object of type B, it will still bind as type B, that's why it's executing the method in class B and not in class A. Note that you are NOT creating an object of type Asince you're not using new.

And as Mike Samuel said, by default -6 should be considered an int, but that doesn't fit with your explanation. I'll try to find out a proper answer for this.

Upvotes: 0

Miserable Variable
Miserable Variable

Reputation: 28752

z.f(-6);

Static type of z is A, which has only one method named f. That method takes double parameter, to which the literal value -6 can be promoted. So at compile time the call is bound to A.f(double).

At runtime z is found to be of type B, which overrides A.f(double) with its own B.f(double), and so that this the method that gets called.

Upvotes: 3

Mike Samuel
Mike Samuel

Reputation: 120486

The static type of z is A so z.f(-6) can only bind to a method in A, which in this case is A.f(int).

The language is designed this way so that

A z = new B(3.0);
z.f(-6);

will always behave the same as

A z = complicatedWayToComputeTrue() ? new B(3.0) : new A(3.0);
z.f(-6);

If the compiler were to bind to a different method signature because it can prove that A z always holds a B then this would introduce all kinds of non-local effects to the language making it really hard to debug or maintain java programs.

Imagine someone trying to maintain

final A z = complicatedWayToComputeTrue() ? new B(3.0) : new A(3.0);
// 1000 lines elided
z.f(-6);

by changing it to

A z = new B(3.0);
// 1000 lines elided
z.f(-6);

If the compiler can now prove that A is always a B and binds Z.f to a method in B, the maintainer will be baffled.

Upvotes: 3

Related Questions