簡體   English   中英

如何定義必須在接口內覆蓋的常量?

[英]How do I define constants that must be overridden inside an interface?

為了制作供玩家選擇的工具包,我制作了一個界面:

public interface Kit {}

我已經為每個套件實現了它:

public class Ninja implements Kit {}

現在,我想設置一些與類有關的常量,而不是實例。 我希望這些接口在接口的所有實現中都是靜態的,並且希望每個實現都覆蓋它們。

嘗試#1:

public interface Kit {
    String DISPLAY_NAME;
    // The blank final field DISPLAY_NAME may not have been initialized
}

嘗試#2:

public interface Kit {  
    static String getDisplayName();
    // Illegal modifier for the interface method getDisplayName; only public & abstract are permitted
}

接口不能像類可以保存字段那樣保存數據。 如果您不希望實例化Kit ,則很可能需要抽象類。 將它們視為可以具有一些實現和字段的接口。

注意,請閱讀以進一步澄清: 閱讀更多

因此,您希望在背景中有一個抽象類,而不是一個接口。 現在看起來如何?

public abstract class Kit {
    protected final String name = "Foo";

    public String getName () {
        return name;
    }
}

這里有我們的工具包,每個實現Kit類都可以訪問name字段。 如果它應該是常量,我可能建議將其大寫。 最好還具有靜態屬性。 可以在這里閱讀更多內容。

為了說明這一點,我從abstract class Kit繼承了兩個類。 NinjaTest

public class Ninja extends Kit {
}

此類的目的只是檢查name確實具有Foo的值。

然后,我們還需要實際的測試類。

public class Test extends Kit {
    public static void main (String[] args) {
        Test ninja = new Test ();
        System.out.println(ninja.getName());    // foo
        Ninja ninja2 = new Ninja ();
        System.out.println(ninja2.getName());   // foo
    } 
}

它們都是不同的類型,請分別Test Ninja但它們在name字段中都具有foo的值。 對於從Kit繼承的每個類都是如此。

如果必須重寫,則建議添加Kitconstructor ,以強制用戶從基類中添加數據。

public abstract class Kit {
    protected String name;

    public Kit (String name) {
        this.name = name;
    }

    public String getName () {
        return name;
    }
}

現在,從Kit繼承的每個類都必須調用super (String) ,這意味着將為每個對象設置name字段。 它可以不同於class A extends Kitclass B extends Kit 這是您搜索的內容嗎?

如果是這樣,那么實現class Aclass B將遵循這些原則。

class A extends Kit {
    public A (String name) {
        super (name);
    }
}

對於B ,將是以下內容。

class B extends Kit {
    public B (String name) {
        super (name);
    }
}

現在它們是不同的類,可以容納不同的字段和方法,但是它們都需要設置基類的name字段: Kit

靜態方法不是虛擬的,這意味着您不能在接口上定義抽象的靜態方法,並且期望它在子類級別被覆蓋和調用,例如:

// Doesn't even compile!
public interface Kit {
  static String name();
}

public class Ninja implements Kit {
  @Override public static name() { return "Ninja"; }
}

如果您需要在給定類的范圍內將值定義為運行時常量(例如,所有Ninja實例必須返回"NINJA" ),則可以在類級別使用常規,非靜態,虛擬方法或否則使用類似注射的東西

public class KitTranslator {
  public void translate(Kit kit) {
    // ...
  }
}

然后,您可以確保應用程序中僅存在一個KitTranslator

我強烈建議不要使用任何涉及static實現,因為它遲早會干擾應用程序的初始化順序,並且因為static字段會不確定地傳播到用戶空間。 另外,由於static在任何級別都不是虛擬的,因此在需要擴展代碼時會遇到麻煩。

最簡單的方法是要求子類包含一些特定的靜態字段

/**
 * subclass MUST define static field "KIT_NAME" !!!!
 */
public interface Kit

---

public class Ninja implements Kit

    public static final String KIT_NAME = "Ninja"

編譯器無法強制執行此要求。 這是程序員必須遵循的約定。 這不是一個大問題。

在運行時,使用反射從子類讀取字段。


另一種更奇妙的方法是使用注釋

@KitInfo(name="Ninja")
public class Ninja implements Kit

這比靜態字段好一點。 您甚至可以編寫一個預處理器來強制必須為Kit的任何子類添加@KitInfo注釋。 (預處理器不能做什么?:)


現在,為了樂趣,讓我們用泛型來解決它

public interface Kit<I extends Kit.Info>
{
    public interface Info
    {
        String name();
    }
}

public class Ninja implements Kit<Ninja.Info>
{
    public static class Info implements Kit.Info
    { 
        public String name(){ return "Ninja"; }
    }
}

在運行時,給定Kit的子類,我們可以使用反射來獲取I的具體類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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