如何定义必须在接口内重写的常量?

时间:2015-06-10 17:00:07

标签: java interface constants java-7

要创建玩家可以选择的工具包,我已经创建了一个界面:

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
}

3 个答案:

答案 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继承了两个类。 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和。 Ninjafoo字段中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 Kitclass A不同。那是你搜索过的吗?

如果是这样,那么实施class Bclass 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的具体类型。