簡體   English   中英

類中的靜態方法與接口中的默認方法具有相同的簽名

[英]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 {

}

以下是我的問題:

  1. 我知道實例方法將覆蓋默認方法但是如果類中的靜態方法與Interface中的默認方法具有相同的簽名呢?

  2. 如果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()是靜態的,不能被覆蓋,因此它不能被認為是Im1()實現,因此編譯問題。

希望有所幫助!

我會回答你的第一個問題,因為第二個問題已經回答了

我知道實例方法將覆蓋默認方法但是如果類中的靜態方法與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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM