要创建玩家可以选择的工具包,我已经创建了一个界面:
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 :(得分:2)
接口不能像类可以容纳字段那样保存数据。如果您不希望实例化Kit
,则很可能需要抽象类。将它们视为可以具有一些实现和字段的接口。
请注意,请阅读以进一步澄清: Read More
所以你想要的是在后台有一个抽象类,而不是一个接口。现在看起来怎么样?
public abstract class Kit {
protected final String name = "Foo";
public String getName () {
return name;
}
}
我们有了这个工具包,每个实施Kit
的班级都可以访问name
字段。如果它应该是一个常数,我可能会建议把它放在帽子里。静态属性也许最好。更多内容可以阅读here。
为了说明我已经从我们的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
但foo
字段中name
的价值均为Kit
。对于从constructor
继承的每个类都是如此。
如果必须覆盖是一项要求,那么我建议添加Kit
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
字段:# redirect gcc -v to stdout && count the number of occurrences
GCC_WITH_LD := $(shell gcc -v 2>&1 | grep -c "\--with-ld")
ifeq ($(GCC_WITH_LD),0)
$(shell echo --with-ld NOT FOUND 1>&2) # print to stderr
# exit using error directive?
else
$(shell echo --with-ld FOUND 1>&2) # print to stderr
endif
mytarget:
@echo myjobs
。
答案 1 :(得分: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
字段会不确定地传播到用户空间。此外,由于静态不是任何级别的虚拟,因此当您需要扩展代码时,您会遇到麻烦。
答案 2 :(得分: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"; }
}
}
在运行时,给定Kit的子类,我们可以使用反射来获得I
的具体类型。