charles_ma
charles_ma

Reputation: 786

method signature in inheritance

In the code below

class A {
    public void v(int... vals) {
        System.out.println("Super");
    }
}

class B extends A {
    @Override
    public void v(int[] vals) {
        System.out.println("Sub");
    }
}

Then I can call new B().v(1, 2, 3);//print Sub rather than Super which is ridiculous but does work well. If I change B to

class B {
    public void v(int[] vals) {
        System.out.println("Not extending A");
    }
}

the call to new B().v(1, 2, 3); will be invalid. You have to call it as new B().v(new int[]{1, 2, 3});, why?

Upvotes: 7

Views: 433

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1503040

Under JDK 1.7, neither of your examples compiles, and I don't believe they should.

It's easy to see why the second version doesn't - when B doesn't extend A, there's no indication of varargs at all, so there's no reason why the compiler should possibly convert an argument list of three int arguments into a single int[]. The more interesting situation is where B does extend A.

The compiler finds a signature of v(int[] vals) which doesn't use varargs. There's nothing in the spec to say it should look up the inheritance chain to find whether one of the other declarations (there could be multiple ones) uses varargs. The fact that it appears to in your version of JDK 1.6 suggests that was a compiler bug which has since been fixed. (I've just reproduced the bug in JDK 1.6.0_39 as well.)

Basically, if you want to be able to invoke B.v() in a varargs-style syntax, B.v() should be declared using varargs. Of course, if you change it so that the compile-time type is A, that would work:

A a = new B();
a.v(1, 2, 3);

Or even (ick):

((A) new B()).v(1, 2, 3);

Note that if you compile with -Xlint you get a warning about B anyway:

Test.java:14: warning: v(int[]) in B overrides v(int...) in A; overriding method
 is missing '...'
    public void v(int[] vals) {
                ^

Upvotes: 7

Marconius
Marconius

Reputation: 713

It doesn't work work because of the way vararg works.

If your method is:

foo(int... par)

foo(new int[]{1, 2, 3});
foo(1, 2, 3);

These are both valid method calls. However, it doesn't work the other way around.

If your method is:

bar(int[] par)

bar(new int[]{1, 2, 3}); // Valid
bar(1, 2, 3); // Invalid!

The second call will be invalid. If the method has a vararg parameter, it can accept an array; if it has an array parameter, it can only accept an array, not a sequence of parameters!

Upvotes: 0

Related Questions