简体   繁体   English

为什么接口不能有字段?

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

Ignore everything up until the second edit忽略所有内容直到第二次编辑

I am trying to do something like this:我正在尝试做这样的事情:

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

My reason for trying to do this is this: I have a class SpecificModifier implements IModifier and there are many very similar class that also implement IModifier.我尝试这样做的原因是:我有一个类 SpecificModifier 实现了 IModifier,并且有许多非常相似的类也实现了 IModifier。 I want every class that implements IModifier to have a public String nameTag.我希望每个实现 IModifier 的类都有一个公共字符串 nameTag。

Edit: I have gotten confirmation that I cannot do this, but can someone explain WHY an interface cannot require a field?编辑:我已经确认我不能这样做,但是有人可以解释为什么接口不能需要字段吗?

Edit two:编辑二:

My understand of the purpose of abstract classes vs interfaces.我对抽象类与接口的目的的理解。 An interface is used purely to declare necessary parts of whatever implements it, so that all the objects have common parts that can be referenced.接口纯粹用于声明实现它的任何内容的必要部分,以便所有对象都有可以引用的公共部分。 While an abstract class is used to provide common functionality to multiple classes.而抽象类用于为多个类提供通用功能。

That is a little bit of an over simplification but regardless, I still see no reason, other than an oversight by the language designers, that an interface cannot have an abstract field.这有点过于简单化了,但无论如何,除了语言设计者的疏忽之外,我仍然没有理由认为接口不能具有抽象字段。

Can anyone provide a reason why?任何人都可以提供一个原因吗?

An Interface specifies a contract, which a concrete class that implements the Interface must adhere to.接口指定一个契约,实现该接口的具体类必须遵守该契约。 This contract describes how an implementation should act.这个契约描述了一个实现应该如何行动。 In the Interface specification, there should be clear comments that describe what the purpose of each method is.在接口规范中,应该有明确的注释来描述每个方法的目的是什么。 The use of an Interface decouples the contract from the actual implementation.接口的使用将契约与实际实现分离。 Fields are an implementation detail, as fields do not describe how a class should "act as."字段是一个实现细节,因为字段不描述类应该如何“充当”。

For instance, Interfaces are commonly used as a declared type and a concrete implementation is used as an actual type.例如,接口通常用作声明类型,而具体实现用作实际类型。

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

Consider the java.util.Map Interface for a moment.考虑一下 java.util.Map 接口。 It describes how a Map should act, via its set of methods.它通过一组方法描述了 Map 应该如何操作。 There are several different implementations of the Map interface that allow users to choose the correct implementation for their needs. Map 接口有几种不同的实现,允许用户根据自己的需要选择正确的实现。

Specifying that a field must be used by several sub classes implies that there is some semblance of a class hierarchy.指定一个字段必须由多个子类使用意味着存在某种类层次结构。 In this case an abstract class could do the trick.在这种情况下,抽象类可以解决问题。

   abstract class IModParent implements IModifier{
      protected String nameTag;
   }

Now you can have a concrete class.现在你可以有一个具体的类。

   class SpecificModifier extends IModParent{

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

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

And a declaration.和宣言。

    IModifier imod = new SpecificModifier("MyName");

This gives you the flexibility of using an Interface type while still being able to share implementation details via a non-instantiable abstract class across the group of concrete classes that you want.这使您可以灵活地使用接口类型,同时仍然能够通过不可实例化的抽象类在所需的具体类组之间共享实现细节。

No, you can't sadly.不,你不能悲伤。 Interfaces in java can only contain methods and constants. java中的接口只能包含方法和常量。 But , there is an alternative to this.但是,有一个替代方案。 Add a method like this:添加一个这样的方法:

String getNameTag();

See?看? that way, the implementations must contain a nameTag field, or they can just do some other stuff to return a string.那样的话,实现必须包含一个nameTag字段,或者他们可以做一些其他的事情来返回一个字符串。

Also, as far as I know, you don't need to add access modifiers to interface methods.此外,据我所知,您不需要为接口方法添加访问修饰符。

Interface is made for methods and constants.接口是为方法和常量创建的。

You need to use abstract class as per your requirements.您需要根据您的要求使用abstract class

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

Now answer to your question WHY an interface cannot require a field?现在回答您的问题WHY an interface cannot require a field? Ans: Because that is the feature of abstract class . Ans:因为那是abstract class的特性。 It would be almost no difference between interface and abstract class . interfaceabstract class之间几乎没有区别。

I hope that I answered your tricky question.我希望我回答了你棘手的问题。

From the perspective of design: Interface defines a contract of agreed behavior which is what can be done aka methods.从设计的角度来看:接口定义了一个约定行为的契约,它是可以做的,也就是方法。 (Eg int getAge() ) and less of how to do it. (例如 int getAge() )和更少的方法。 Then Instance Fields (int age) which are more in part what u need to achieve the behavior doesnt naturally fit.然后是实例字段(int age),它们更多地是您实现行为所需的部分并不自然适合。 And Static final fields that are not implementation specific (Eg static final int CENTURIONAGE=100) is still availble on interface.并且非实现特定的静态最终字段(例如静态最终 int CENTURIONAGE=100)在接口上仍然可用。

Then after agreeing on the contract, if you go to behavior implementation you go on to classess and abstract classes etc.然后在同意契约之后,如果你去行为实现,你就会去类和抽象类等。

No.不。

Interfaces can only require methods, not fields (or constructors).接口只能需要方法,不能需要字段(或构造函数)。

You could probably achieve the same effect by putting a getter and/or setter method in the interface.您可以通过在接口中放置 getter 和/或 setter 方法来实现相同的效果。

If you look up the java docs, you will get the actual statements from there.如果您查找 java 文档,您将从那里获得实际的语句。

Abstract classes are similar to interfaces.抽象类类似于接口。 You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.您不能实例化它们,它们可能包含声明有或没有实现的混合方法。 However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.但是,使用抽象类,您可以声明非静态和最终的字段,并定义公共、受保护和私有的具体方法。 With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public.对于接口,所有字段都自动是 public、static 和 final,并且您声明或定义的所有方法(作为默认方法)都是 public。 In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.此外,您只能扩展一个类,无论它是否是抽象的,而您可以实现任意数量的接口。

Which should you use, abstract classes or interfaces?你应该使用哪个,抽象类或接口?

Consider using abstract classes if any of these statements apply to your situation:如果以下任何陈述适用于您的情况,请考虑使用抽象类:

  1. You want to share code among several closely related classes.您希望在几个密切相关的类之间共享代码。
  2. You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).您希望扩展抽象类的类具有许多通用方法或字段,或者需要公共以外的访问修饰符(例如 protected 和 private)。
  3. You want to declare non-static or non-final fields.您想声明非静态或非最终字段。 This enables you to define methods that can access and modify the state of the object to which they belong.这使您能够定义可以访问和修改它们所属对象状态的方法。

Consider using interfaces if any of these statements apply to your situation:如果以下任何陈述适用于您的情况,请考虑使用接口:

1.You expect that unrelated classes would implement your interface. 1.您期望不相关的类会实现您的接口。 For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.例如,接口 Comparable 和 Cloneable 由许多不相关的类实现。

2.You want to specify the behavior of a particular data type, but not concerned about who implements its behavior. 2.您想指定特定数据类型的行为,但不关心谁实现其行为。

3.You want to take advantage of multiple inheritance of type. 3.你想利用类型的多重继承。

However, based on your question first edit, you could define a field in an interface, however there is a caveat.但是,根据您的问题首次编辑,您可以在界面中定义一个字段,但是有一个警告。 its has to be public , static and final .它必须是公开的静态的最终的 In other words, define only constants ;)换句话说,只定义常量;)

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

The above code will compile.上面的代码会编译。

Here's what I have done in many projects to be able to define an "interface" that defines not fields but a "contract" for fields.这是我在许多项目中所做的,以便能够定义一个“接口”,该“接口”不是定义字段而是定义字段的“合同”。

The suggestion made earlier in this topic to use abstract base classes has a severe limitation.本主题前面提出的使用abstract基类的建议有一个严重的局限性。 A concrete class can implement multiple interfaces in Java's limited form of multiple inheritance, but... it can only extend one base class.一个具体的类可以在 Java 的多重继承的有限形式中实现多个接口,但是……它只能extend一个基类。 That means that the base class method only works for one interface that requires a contract for fields.这意味着基类方法仅适用于需要字段约定的接口。

In the way of a use case, suppose I wanted a contract/interface for several kinds of domain objects:以用例的方式,假设我想要几种域对象的合同/接口:

  • Objects with an expiration date具有到期日期的对象
  • Objects with audit trails (created by, created dated,....)具有审计跟踪的对象(创建者、创建日期、...)

I may have objects which can expire but don't need audit trails.我可能有可以过期但不需要审计跟踪的对象。 I may have other objects which are the opposite: they need audit trails, but don't have expiration dates.我可能有其他相反的对象:它们需要审计跟踪,但没有到期日期。

Base classes don't allow for a sorta "pick and choose" among these.基类不允许在其中进行某种“挑选”。 Any base class would have to define both, or you'd have to have base classes for ALL combinations.任何基类都必须定义两者,或者您必须为所有组合都定义基类。

Here's my solution and it has worked quite well: I define the setters and getters as abstract methods in the interface.这是我的解决方案,它运行良好:我将 setter 和 getter 定义为接口中的抽象方法。 You leave the implementation to the concrete classes.您将实现留给具体的类。

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

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

A concrete class that is both Audtiable (using String to identify a user) and Expirable would look like this (I'm using Lombok)一个既可审计(使用String来识别用户)又可过期的具体类看起来像这样(我正在使用 Lombok)

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

This allows concrete objects to select which interfaces they use.这允许具体对象选择它们使用的接口。 You do have to DEFINE the fields, but it is often a "good thing" to define them in concrete types but implement the contract of an inteface.您确实必须定义字段,但在具体类型中定义它们但实现接口契约通常是一件“好事”。 An example of why, would be to allow each concrete class to determine things like:原因的一个例子是允许每个具体类确定以下内容:

  • The data type (as in the user type for Auditable )数据类型(如Auditable的用户类型)
  • Annotations for persistence or serialization (Hibernate, JPA, Jackson, Gson, etc.)持久化或序列化注解(Hibernate、JPA、Jackson、Gson 等)
  • Custom initializations or protection levels自定义初始化或保护级别

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

相关问题 为什么我不能只有字母大小写的java类名和接口名? - Why can't I have a java class name and interface name that only differ in letter case? 为什么抽象类不能扩展接口? - Why can't an abstract class extend an interface? 为什么无法使用Number接口进行计算? - Why can't I calculate with Number interface? 为什么接口和抽象方法无法实例化? - why interface and abstract methods can't be instantiated? 为什么不能使用代理到AIDL接口? - Why can't use proxy to AIDL interface? 为什么接口方法在实现接口的类中不能是静态的? - Why interface methods can't be static in class that implements the interface? 为什么Spring在TransactionSynchronization接口中没有回滚方法? - Why Spring doesn't have rollback methods in TransactionSynchronization interface? 为什么Java中的DataInput接口没有readUnsignedInt方法 - Why DataInput interface in Java doesn't have readUnsignedInt method 为什么我的界面没有JLS声明的方法? - Why doesn't my interface have the methods the JLS says it declares? 为什么Java编译器无法识别字段已初始化? - Why doesn't the java compiler recognise fields have been initialized?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM