简体   繁体   中英

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. I want every class that implements IModifier to have a public String 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. It describes how a Map should act, via its set of methods. There are several different implementations of the Map interface that allow users to choose the correct implementation for their needs.

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. 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.

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.

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

Now answer to your question WHY an interface cannot require a field? Ans: Because that is the feature of abstract class . It would be almost no difference between interface and abstract 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. Then Instance Fields (int age) which are more in part what u need to achieve the behavior doesnt naturally fit. And Static final fields that are not implementation specific (Eg static final int CENTURIONAGE=100) is still availble on interface.

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.

If you look up the java docs, you will get the actual statements from there.

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. 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).
  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. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.

2.You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.

3.You want to take advantage of multiple inheritance of type.

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. A concrete class can implement multiple interfaces in Java's limited form of multiple inheritance, but... it can only extend one base class. 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. 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)

@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 )
  • Annotations for persistence or serialization (Hibernate, JPA, Jackson, Gson, etc.)
  • Custom initializations or protection levels

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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