![](/img/trans.png)
[英]what will happen when a class implement two interface having same method signature but different modifier default and static
[英]static method in class have same signature as default method in interface
我有以下情況:
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 {
}
以下是我的問題:
我知道實例方法將覆蓋默認方法但是如果類中的靜態方法與Interface中的默認方法具有相同的簽名呢?
如果class C
靜態方法m1()
是公共的,那么編譯錯誤將是:
靜態方法m1()與I.中的抽象方法沖突
因此,當訪問修飾符是默認值時,它試圖隱藏,當它是公共時,它是沖突的。 為什么會有這種差異? 它背后的概念是什么?
歸根結底,當你有這樣的事情:
class Me {
public static void go() {
System.out.println("going");
}
}
這兩個都是允許的:
Me.go();
Me meAgain = new Me();
meAgain.go(); // with a warning here
Intersting是這樣的,例如:
Me meAgain = null;
meAgain.go();
就個人而言,我仍然認為這是因為兼容性無法收回的設計缺陷 - 但我希望編譯器不允許我從實例訪問靜態方法。
你的第一個問題與java-8本身無關,它在java-8之前是這樣的:
interface ITest {
public void go();
}
class Test implements ITest {
public static void go() { // fails to compile
}
}
默認方法只是遵循相同的規則。 為什么出現這種情況實際上是詳細的堆棧溢出了不少-但基本思想是, 可能這會導致上調用哪個方法混亂(想象ITest
將是一類Test
會延伸你做ITest test = new Test(); test.go()
; - >你打電話給哪個方法?)
我認為出於同樣的原因,這也是不允許的(這基本上是你的第二個問題,否則你會有一個具有相同簽名的靜態和非靜態方法)
static class Me {
static void go() {
}
void go() {
}
}
有趣的是,這有點固定(我猜他們意識到在方法引用中再次犯同樣的錯誤真的很糟糕):
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
回答你的第一個問題:
“類中的靜態方法”和“接口中的默認方法”都可用於Main
類,因此如果它們具有相同的簽名,則會產生歧義。
例如:
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();
}
}
輸出: m1 from C
同樣的,
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();
}
}
輸出: m1 from I
如您所見,這兩個都可以類似地訪問。 因此,當您實現I並擴展C時,這也是沖突的原因。
回答你的第二個問題:
如果您的分類和接口在同一個包中,則默認和公共訪問修飾符應該類似。
另外, C
m1()
是靜態的,不能被覆蓋,因此它不能被認為是I
中m1()
實現,因此編譯問題。
希望有所幫助!
我會回答你的第一個問題,因為第二個問題已經回答了
我知道實例方法將覆蓋默認方法但是如果類中的靜態方法與Interface中的默認方法具有相同的簽名呢?
我假設您正在使用JDK 1.8,因此混淆。 接口方法中的default
修飾符不是在談論其訪問規范。 相反,它提到接口本身需要實現此方法。 該方法的訪問規范仍然是公開的。 從JDK8開始,接口允許您使用默認修飾符指定方法,以允許以向后兼容的方式擴展接口。
在您的界面中,您必須為編譯提供default void m1() {}
才能成功。 通常我們只是以一種抽象的方式定義它們,如void m1();
在接口中您必須實現該方法,因為您將該方法指定為默認方法。 希望你能理解。
因為java中的類方法也可以使用實例變量來調用,所以這個結構會導致含糊不清:
Main m = new Main();
m.m1();
目前還不清楚最后一個語句是應該調用類方法C.m1()
還是實例方法I.m1()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.