为什么界面没有字段?

时间:2015-08-26 00:12:14

标签: java interface

在第二次编辑之前忽略所有内容

我正在尝试做这样的事情:

public interface IModifier{
   public String nameTag;
   public void foo();
}

我尝试这样做的原因是: 我有一个类SpecificModifier实现IModifier 并且有许多非常相似的类也实现了IModifier。 我希望每个实现IModifier的类都有一个公共String nameTag。

编辑:我已经确认我不能这样做,但有人可以解释为什么界面不能要求字段吗?

编辑二:

我理解抽象类与接口的目的。接口纯粹用于声明实现它的任何必要部分,以便所有对象都具有可以引用的公共部分。虽然抽象类用于为多个类提供通用功能。

这有点过于简化,但无论如何,除了语言设计师的疏忽之外,我仍然认为没有理由说接口不能有抽象的字段。

任何人都可以提供理由吗?

7 个答案:

答案 0 :(得分:4)

接口指定一个契约,实现接口的具体类必须遵守该契约。该合同描述了实施应如何行动。在接口规范中,应该有明确的注释来描述每种方法的用途。使用接口将合同与实际实现分离。字段是一个实现细节,因为字段不描述类应如何“充当”。

例如,Interfaces通常用作声明类型,具体实现用作实际类型。

    Map<Key,Value> m = new HashMap<>();

暂时考虑java.util.Map接口。它通过一组方法描述了地图应该如何行动。 Map接口有几种不同的实现,允许用户根据需要选择正确的实现。

指定某个字段必须由多个子类使用意味着存在类层次结构的某些外观。在这种情况下,抽象类可以做到这一点。

   abstract class IModParent implements IModifier{
      protected String nameTag;
   }

现在你可以有一个具体的课程。

   class SpecificModifier extends IModParent{

      SpecificModifier(String nameTag){ this.nameTag = nameTag; }

      @Override
      public void foo(){ System.out.println(nameTag); }
   }

宣言。

    IModifier imod = new SpecificModifier("MyName");

这使您可以灵活地使用接口类型,同时仍然可以通过您想要的具体类组中的不可实例化的抽象类来共享实现细节。

答案 1 :(得分:2)

不,你不能遗憾。 java中的接口只能包含方法和常量。 ,还有其他选择。添加如下方法:

String getNameTag();

请参阅?这样,实现必须包含nameTag字段,或者他们可以只做一些其他的东西来返回字符串。

另外,据我所知,您不需要为接口方法添加访问修饰符。

答案 2 :(得分:1)

接口是针对方法和常量的。

您需要根据自己的要求使用abstract class

public abstract class IModifier{
   public String nameTag;
   public abstract void foo();
}

现在回答你的问题WHY an interface cannot require a field? 答:因为这是abstract class的特征。 interfaceabstract class之间几乎没有区别。

我希望我回答你那个棘手的问题。

答案 3 :(得分:1)

从设计的角度来看: 接口定义了约定行为的契约,这也就是方法。 (例如,int getAge())而不是如何做到这一点。 然后实例字段(int age)更多部分是你需要实现的行为并不适合。并且非特定于实现的静态最终字段(例如,静态最终int CENTURIONAGE = 100)仍可在界面上使用。

然后在同意合同之后,如果你去行为实施,你会继续讨论和抽象类等。

答案 4 :(得分:0)

没有

接口只能要求方法,而不是字段(或构造函数)。

您可以通过在界面中放置getter和/或setter方法来实现相同的效果。

答案 5 :(得分:0)

如果您查找Java文档,则会从那里获取实际的语句。

抽象类类似于接口。您无法实例化它们,它们可能包含使用或不使用实现声明的方法的混合。但是,使用抽象类,您可以声明非静态和最终字段,并定义公共,受保护的和私有的具体方法。使用接口时,所有字段都自动是公共的,静态的和最终的,并且您声明或定义的所有方法(作为默认方法)都是公共的。此外,无论是否抽象,您都只能扩展一个类,而您可以实现任何数量的接口。

您应该使用哪个抽象类或接口?

如果以下任何一种情况适用于您的情况,请考虑使用抽象类:

  1. 您想在几个密切相关的类之间共享代码。
  2. 您期望扩展您的抽象类的类具有许多共同点 方法或字段,或者要求访问修饰符不是公共的(例如受保护的和私有的)。
  3. 您要声明非静态或非最终字段。这使您能够定义一些方法,这些方法可以访问和修改它们所属对象的状态。

如果以下任何一种情况适合您的情况,请考虑使用接口:

1。您期望不相关的类将实现您的接口。例如,     Comparable和Cloneable接口由许多不相关的类实现。

2。您想指定特定数据类型的行为,但不关心谁    实现其行为。

3。您想利用类型的多重继承。

但是,根据您的问题的第一个编辑,您可以在界面中定义一个字段,但是有一个警告。它必须是公开静态最终。 换句话说,只定义常量;)

public interface TimeClient {

public static final String TIME_ZONE = "Europe/Amsterdam";    //Defines a static field     

static public ZoneId getZoneId(String zoneString) {
    try {
        return ZoneId.of(zoneString);
    } catch (DateTimeException e) {
        System.err.println("Invalid time zone: " + zoneString
                + "; using default time zone instead.");
        return ZoneId.systemDefault();
    }
}

//Defines a default method
default public ZonedDateTime getZonedDateTime(String zoneString) {
    return ZonedDateTime.of(LocalDateTime.MAX, getZoneId(zoneString));
}}

以上代码将编译。

答案 6 :(得分:0)

这是我在许多项目中所做的,以便能够定义一个“接口”,该“接口”不是定义字段而是定义字段的“合同”。

本主题前面提出的使用 abstract 基类的建议有一个严重的限制。一个具体的类可以在 Java 的多重继承的有限形式中实现多个接口,但是……它只能 extend 一个基类。这意味着基类方法仅适用于需要字段约定的接口。

就用例而言,假设我想要一个用于多种领域对象的合同/接口:

  • 具有到期日期的对象
  • 具有审计跟踪的对象(创建者、创建日期……)

我可能有可能过期但不需要审计跟踪的对象。我可能还有其他相反的对象:它们需要审计跟踪,但没有到期日期。

基类不允许在其中进行某种“挑选”。任何基类都必须同时定义,否则您必须为所有组合都定义基类。

这是我的解决方案,而且效果很好:我将 setter 和 getter 定义为接口中的抽象方法。您将实现留给具体的类。

public interface Auditable<USER_TYPE> {
    Instant getCreatedOn();
    void setCreatedOn(Instant)

    USER_TYPE getCreatedBy();
    void setCreatedBy(USER_TYPE creator);

既可审计(使用 String 标识用户)又可过期的具体类看起来像这样(我使用的是 Lombok)

@Getter @Setter
public AuditableExpirableObject implement Auditable<String>, Expirable {
    private String createdBy
    private Instant createdOn;
    private Instant expirationDate;

这允许具体对象选择它们使用的接口。您确实必须定义字段,但在具体类型中定义它们但实现接口契约通常是一件“好事”。原因的一个示例是允许每个具体类确定以下内容:

  • 数据类型(如 Auditable 的用户类型)
  • 用于持久化或序列化的注释(Hibernate、JPA、Jackson、Gson 等)
  • 自定义初始化或保护级别