2015-06-10 10 views
1

要創建工具包,玩家可以選擇,我做了一個接口:如何定義必須在界面內重寫的常量?

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 
} 
+0

所以你想要所有的類都有一個唯一的名字,但要確保所有的實現都有'String getName()'方法?對我來說,聽起來更像是抽象類而不是界面。 – Emz

+0

@Emz _implementations_是什麼意思? –

+0

當你'忍者=新的忍者();忍者B =新的忍者();'你想'了'和'B'能夠有不同的價值觀?在他們的名字領域,雖然仍然確保他們有名字領域? – Emz

回答

2

一個接口不能保持數據的類可以保持場的方式。如果你不想讓你的Kit被實例化,你很可能需要一個抽象類。把它們看作一個可以有一些實現和字段的接口。

注意,請閱讀進一步clarfication:Read More

所以,你要在這個東西有一個抽象類的背景,而不是一個接口。現在看起來如何?

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

    public String getName() { 
     return name; 
    } 
} 

這裏,我們有我們的工具包,實現Kit每類將有機會獲得name領域。如果它應該是一個常量,我可能會建議將它放在大寫字母上。對於靜態屬性也可能是最好的。更多的可以閱讀here

爲了說明我已經從我們的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 RESP。 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

0

靜態方法是不是虛擬的,這意味着你不能定義一個接口上的抽象靜態方法,並期望它被覆蓋,並在子類級別喜歡叫:

// 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在任何級別都不是虛擬的,所以當你需要增加代碼時,你會遇到麻煩。

0

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

/** 
* 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 

這比靜態字段更好一點。你甚至可以編寫一個預處理器來強制@KitInfo必須註明Kit的任何子類。 (什麼不能用預處理做呢?:)現在


,對於它的樂趣,讓我們,我們來解決它的仿製藥

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"; } 
    } 
} 

在運行時給出套件的一個子類,我們可以使用反射來獲得I的具體類型。