2015-06-10 2 views
1

Чтобы создать наборы, которые игроки могут выбирать, я сделал интерфейс:Как определить константы, которые должны быть переопределены внутри интерфейса?

public interface Kit {} 

И я реализовал это для каждого набора:

public class Ninja implements Kit {} 

Теперь я хочу установить некоторые константы, относящиеся к класс, а не экземпляр. Я хочу, чтобы они были статичными во всех реализациях интерфейса, и я хочу, чтобы каждая реализация переопределяла их.

Try # 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

Когда вы делаете 'Ninja a = new Ninja(); Ninja b = new Ninja(); 'вы хотите, чтобы' a' и 'b' могли иметь разные значения? Из поля 'name ', но все же убедитесь, что у них есть поля имен? – 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. 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.

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

Во время выполнения, данный подкласс Kit, мы можем используйте отражение, чтобы получить конкретный тип I.

Смежные вопросы