static method in class have same signature as default method in interface
Asked Answered
B

4

12

I have below scenario :

class C {
    static void m1() {}
}

interface I {
    default void m1() {}
}

//this will give compilation error : inherited method from C cannot hide public abstract method in I
class Main extends C implements I {

}

Below are my questions:

  1. I am aware that instance method will override the default methods but what if static methods in class have same signature as default method in Interface?

  2. If static method m1() in class C would be public then compilation error will be :

    static method m1() conflicts with abstract method in I.

so when the access modifier was default it was trying to hide and when it is public it is conflicting. why is this difference? what is the concept behind it?

Bloodandthunder answered 9/8, 2017 at 5:16 Comment(3)
Which compiler are you using?Inexperience
This should not depend on the presence of default implementations or access levels - the compilation error should be the same, in my opinion. In eclipse, it is always "This static method cannot hide the instance method from I", with oracle jdk 1.8.0_121 "[path]/A.java:[5,17] m1() in [path].A cannot implement m1() in [path].I overriding method is static "Inexperience
I am using 1.8 as well, it show different compile errorsBloodandthunder
D
5

Ultimately that boils down to the fact that when you have something like this:

class Me {
    public static void go() {
        System.out.println("going");
    }
}

These both would be allowed:

Me.go();
Me meAgain = new Me();
meAgain.go(); // with a warning here

Intersting is that this would work too for example:

Me meAgain = null;
meAgain.go();

Personally I still see this as design flaw that could not be retracted due to compatibility - but I wish the compiler would not allow me to access the static method from an instance.

Your first question is not related to java-8 per-se, it has been like this before java-8:

interface ITest {
    public void go();
}

class Test implements ITest {
    public static void go() { // fails to compile

    }
}

default methods just follow the same rule here. Why this happens is actually detailed quite a lot on stack overflow - but the underlying idea is that potentially this would cause confusion on which method to call (imagine ITest would be a class that Test would extends and you do ITest test = new Test(); test.go(); -> which method are you calling?)

I think that for the same reasons this is not allowed also (which is basically your second question, otherwise you would have a static and non-static method with the same signatures)

static class Me {
    static void go() {

    }

    void go() {

    }
}

It's interesting that this is sort of fixed (I guess that they realized it would be really bad to do the same mistake again) in method references:

static class Mapper {
    static int increment(int x) {
        return x + 1;
    }

    int decrement(int x) {
        return x - 1;
    }
}


Mapper m = new Mapper();
IntStream.of(1, 2, 3).map(m::increment); // will not compile
IntStream.of(1, 2, 3).map(m::decrement); // will compile
Damselfish answered 10/8, 2017 at 8:39 Comment(0)
N
1

Answering your 1st question:

Both the "static method in class" and the "default method in interface" are available to the class Main, and hence if they have the same signature, it will create ambiguity.

For example:

class C{
    static void m1(){System.out.println("m1 from C");}
}

public class Main extends C{
    public static void main(String[] args) {
        Main main=new Main();
        main.m1();
    }
}

Output: m1 from C

Similarly,

interface I{
    default void m1(){System.out.println("m1 from I");}
}

public class Main implements I{
    public static void main(String[] args) {
        Main main=new Main();
        main.m1();
    }
}

Output: m1 from I

As you can see, both these can be accessed similarly. So this is also the reason for conflict when you implement I and extend C.

Answering your second question:

If your classed and interfaces are in the same package, the default and public access modifier should work similarly.

Also, m1() in C is static which cannot be overridden, and hence it cannot be considered as implementation of m1() in I and so the compilation issue.

Hope that helps!

Nucleon answered 9/8, 2017 at 6:3 Comment(2)
class and interface are in same package , still the behavior is differentBloodandthunder
If there is anything more than you have mentionedNucleon
C
1

I will answer your first question since the second is already answered

I am aware that instance method will override the default methods but what if static methods in class have same signature as default method in Interface?

I am assuming you are using JDK 1.8 and hence the confusion. default modifier in an interface method is not talking about its access specifications. Instead it mentions that the interface itself need to implement this method. Access specification for the method is still public. Starting from JDK8 , interfaces allow you specify methods with default modifer to allow to extend interfaces in a backward compatible way.

In your interface you had to give default void m1() {} for the compilation to be successfull. Normally we simply define them in an abstract way like void m1(); in an interface You had to implement the method because you specified the method as default. Hope you understand.

Crenelation answered 9/8, 2017 at 6:33 Comment(4)
"Starting from JDK8 , interfaces allow you specify methods with default modifer" - What ist this about? Methods in interfaces are always public (even when no access modifier is given)Contestant
If you read the answer fully, you will understand what I was trying to convey. If you define a method with default modifier ,compiler will force you to implement the method in the interface itself. I thought OP missed this feature since this is new.Crenelation
If you feel I have not put it the right way or you could make it better, feel free to do itCrenelation
No, sorry, that's perfectly fine (I shouldn't write comments at 3:00 am...). You simply referred to docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html , and not to default visibility.Contestant
C
0

Because class methods in java can also be called using instance variables, this construct will lead to ambiguities:

Main m = new Main();

m.m1();

It is unclear if the last statement should call the class method C.m1() or the instance method I.m1().

Cloots answered 9/8, 2017 at 5:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.