112
votes

Why can't Java classes have abstract fields like they can have abstract methods?

For example: I have two classes that extend the same abstract base class. These two classes each have a method that is identical except for a String constant, which happens to be an error message, within them. If fields could be abstract, I could make this constant abstract and pull the method up into the base class. Instead, I have to create an abstract method, called getErrMsg() in this case, that returns the String, override this method in the two derived classes, and then I can pull up the method (which now calls the abstract method).

Why couldn't I just make the field abstract to begin with? Could Java have been designed to allow this?

5
It sounds like you could have sidestepped this entire issue by making the field non-constant and simply supplying the value through the constructor, ending up with 2 instances of one class rather than 2 classes.Nate
By making a fields abstract in a super class, you have specific that every sub class must have this field, so this is no different to a non-abstract field.Peter Lawrey
@peter, i'm not sure i'm following your point. if a non-abstract constant was specified in the abstract class, then it's value is constant through all subclasses as well. if it were abstract, then its value would have to be implemented/supplied by each subclass. so, it would not be the same at all.liltitus27
@liltitus27 I think my point 3.5 years ago was that having abstract fields wouldn't change very much except break the whole idea of separating the user of an interface from the implementation.Peter Lawrey
This would be helpful because it could allow custom field annotations in the child classgeg

5 Answers

114
votes

You can do what you described by having a final field in your abstract class that is initialised in its constructor (untested code):

abstract class Base {

    final String errMsg;

    Base(String msg) {
        errMsg = msg;
    }

    abstract String doSomething();
}

class Sub extends Base {

    Sub() {
        super("Sub message");
    }

    String doSomething() {

        return errMsg + " from something";
    }
}

If your child class "forgets" to initialise the final through the super constructor the compiler will give a warning an error, just like when an abstract method is not implemented.

9
votes

I see no point in that. You can move the function to the abstract class and just override some protected field. I don't know if this works with constants but the effect is the same:

public abstract class Abstract {
    protected String errorMsg = "";

    public String getErrMsg() {
        return this.errorMsg;
    }
}

public class Foo extends Abstract {
    public Foo() {
       this.errorMsg = "Foo";
    }

}

public class Bar extends Abstract {
    public Bar() {
       this.errorMsg = "Bar";
    }
}

So your point is that you want to enforce the implementation/overriding/whatever of errorMsg in the subclasses? I thought you just wanted to have the method in the base class and didn't know how to deal with the field then.

4
votes

Obviously it could have been designed to allow this, but under the covers it'd still have to do dynamic dispatch, and hence a method call. Java's design (at least in the early days) was, to some extent, an attempt to be minimalist. That is, the designers tried to avoid adding new features if they could be easily simulated by other features already in the language.

0
votes

Reading your title, I thought you were referring to abstract instance members; and I couldn't see much use for them. But abstract static members is another matter entirely.

I have often wished that I could declare a method like the following in Java:

public abstract class MyClass {

    public static abstract MyClass createInstance();

    // more stuff...

}

Basically, I would like to insist that concrete implementations of my parent class provide a static factory method with a specific signature. This would allow me to get a reference to a concrete class with Class.forName() and be certain that I could construct one in a convention of my choosing.

0
votes

Another option is to define the field as a public (final, if you like) in the base class, and then initialize that field in the constructor of the base class, depending upon which subclass is currently being used. It's a bit shady, in that it introduces a circular dependency. But, at least it's not a dependency that can ever change -- i.e., the subclass will either exist or not exist, but the subclass's methods or fields can not influence the value of field.

public abstract class Base {
  public final int field;
  public Base() {
    if (this instanceof SubClassOne) {
      field = 1;
    } else if (this instanceof SubClassTwo) {
      field = 2;
    } else {
      // assertion, thrown exception, set to -1, whatever you want to do 
      // to trigger an error
      field = -1;
    }
  }
}