[英]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
繼承了兩個類。 Ninja
和Test
。
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
繼承的每個類都是如此。
如果必須重寫,則建議添加Kit
的constructor
,以強制用戶從基類中添加數據。
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 Kit
和class B extends Kit
。 這是您搜索的內容嗎?
如果是這樣,那么實現class A
和class 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.