繁体   English   中英

为什么接口不能有字段?

[英]Why can't an interface have fields?

忽略所有内容直到第二次编辑

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

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

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

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

编辑二:

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

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

任何人都可以提供一个原因吗?

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

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

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

考虑一下 java.util.Map 接口。 它通过一组方法描述了 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");

这使您可以灵活地使用接口类型,同时仍然能够通过不可实例化的抽象类在所需的具体类组之间共享实现细节。

不,你不能悲伤。 java中的接口只能包含方法和常量。 但是,有一个替代方案。 添加一个这样的方法:

String getNameTag();

看? 那样的话,实现必须包含一个nameTag字段,或者他们可以做一些其他的事情来返回一个字符串。

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

接口是为方法和常量创建的。

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

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

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

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

从设计的角度来看:接口定义了一个约定行为的契约,它是可以做的,也就是方法。 (例如 int getAge() )和更少的方法。 然后是实例字段(int age),它们更多地是您实现行为所需的部分并不自然适合。 并且非实现特定的静态最终字段(例如静态最终 int CENTURIONAGE=100)在接口上仍然可用。

然后在同意契约之后,如果你去行为实现,你就会去类和抽象类等。

不。

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

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

如果您查找 java 文档,您将从那里获得实际的语句。

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

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

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

  1. 您希望在几个密切相关的类之间共享代码。
  2. 您希望扩展抽象类的类具有许多通用方法或字段,或者需要公共以外的访问修饰符(例如 protected 和 private)。
  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));
}}

上面的代码会编译。

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

本主题前面提出的使用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 等)
  • 自定义初始化或保护级别

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM