125

Why can't Java classes have abstract fields like they can with 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?

Jasperan
  • 2,154
  • 1
  • 16
  • 40
Paul Reiners
  • 8,576
  • 33
  • 117
  • 202
  • 3
    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 Feb 06 '10 at 01:25
  • 6
    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 Feb 06 '10 at 09:24
  • @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 Nov 20 '13 at 19:11
  • 1
    @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 Nov 20 '13 at 19:38
  • 1
    This would be helpful because it could allow custom field annotations in the child class – geg May 30 '17 at 18:48

5 Answers5

121

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.

folibis
  • 12,048
  • 6
  • 54
  • 97
rsp
  • 23,135
  • 6
  • 55
  • 69
  • Haven't got an editor to try it here, but this was what I was going to post as well.. – Tim Feb 05 '10 at 23:17
  • 8
    "the compiler will give a warning". Actually, the Child constructor would be trying to use a non-existent noargs constructor and that is a compilation error (not a warning). – Stephen C Feb 06 '10 at 00:15
  • And adding to @Stephen C's comment, "like when an abstract method is not implemented" is also an error, not a warning. – Laurence Gonsalves Feb 06 '10 at 01:58
  • 4
    Good answer - this worked for me. I know it's been a while since it was posted but think `Base` needs to be declared `abstract`. – Steve Chambers Nov 26 '13 at 16:38
  • It will not work for unit tests since they have to be initialized with default constructors. – Yuri Mar 01 '15 at 19:22
  • 4
    I still dislike this approach (even though it's the only way to go) because it adds an extra argument to a constructor. In network programming, I like to make message types, where each new message implements an abstract type but must have a unique designated character like 'A' for AcceptMessage and 'L' for LoginMessage. These ensure that a custom message protocol will be able to put this distinguishing character on the wire. These are implicit to the class, so they'd be best served as fields, not something passed into the constructor. – Adam Hughes Jan 03 '17 at 21:46
  • I don't understand the importance of the 'final' modifier here, can someone clarify? – ImaginationIsPower Aug 14 '22 at 14:59
  • The `final` keyword in this example enforces the attribute to be readonly - can be initialised during construction but not changed afterwards. – rsp Aug 18 '22 at 13:45
8

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.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • That's exactly what I was in the middle of typing. There's only the quick and the dead around here... Except you misspelled "Foo" on the errorMsg. :) – Quick Joe Smith Feb 05 '10 at 22:57
  • 8
    Well, I could do that of course. And I had thought of it. But why do I have to set a value in the base class when I know for a fact that I'm going to override that value in every derived class? Your argument could also be used to argue that there is no value in allowing abstract methods either. – Paul Reiners Feb 05 '10 at 22:59
  • 1
    Well this way not every subclass **has** to override the value. I can also just define `protected String errorMsg;` which enforces somehow that I set the value in the subclasses. It is similar to those abstract classes that actually implement all the methods as placeholders so that developers don't have to implement every method although they don't need it. – Felix Kling Feb 05 '10 at 23:04
  • Erm ... unless I am very mistaken, fields can not be overridden in Java, only shadowed. So getErrorMsg() would always return "" - which is precisely the effect Paul wants to know the reason for. – meriton Feb 05 '10 at 23:07
  • 8
    Saying `protected String errorMsg;` does *not* enforce that you set the value in subclasses. – Laurence Gonsalves Feb 05 '10 at 23:08
  • @meriton: True, so it has to be set in the constructor. – Felix Kling Feb 05 '10 at 23:17
  • @Laurence Gonsalves: Well it enforces in such a way that `errorMsg` would be `NULL` if not it is not set in the subclasses. – Felix Kling Feb 05 '10 at 23:28
  • @Paul -- "But why do I have to set a value in the base class ...". You don't *have to* set the value in the base class. – Stephen C Feb 06 '10 at 00:18
  • 1
    If having the value be null if you don't set it counts as "enforcement", then what would you call non-enforcement? – Laurence Gonsalves Feb 06 '10 at 01:56
  • @Laurence Gonsalves: Giving the field a value in the base class. – Felix Kling Feb 06 '10 at 08:26
  • 10
    @felix, there's a difference between *enforcement* and *contracts*. this whole post is centered around abstract classes, which in turn represent a contract that must be fulfilled by any subclass. so, when we talk about having an abstract field, we are saying that any subclass **must** implement that field's value, per contract. your approach does not guarantee any value, and does not make explicit what's expected, like a contract does. very, very different. – liltitus27 Nov 20 '13 at 19:17
4

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.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • @Laurence - it is *not* obvious to me that abstract fields could have been included. Something like that is likely to have deep and fundamental impact on the type system, and on the language usability. (In the same way that multiple inheritance brings deep problems ... that can bite the unwary C++ programmer.) – Stephen C Feb 06 '10 at 02:45
0

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.

Drew Wills
  • 8,408
  • 4
  • 29
  • 40
  • 1
    Yea well ... this probably means that you are using reflection far to much!! – Stephen C Feb 06 '10 at 00:31
  • Sounds like a strange programming habit to me. Class.forName(..) smells like a design flaw. – whiskeysierra Feb 06 '10 at 01:59
  • These days we basically always use Spring DI to accomplish this sort of thing; but before that framework became known & popular, we would specify implementation classes in properties or XML files, then use Class.forName() to load them. – Drew Wills Feb 07 '10 at 04:33
  • I can give you a use case for them. The absence of "abstract fields" nearly impossible to declare a field of a generic type in an abstract generic class: `@autowired T fieldName`. If `T` is defined as something like `T extends AbstractController`, type erasure causes the field to get generated as type `AbstractController` and which can't be autowired because it's not concrete and not unique. I generally agree there isn't much use for them, and thus they don't belong in the language. What I would not agree with is that there's NO use for them. – DaBlick May 21 '15 at 22:08
0

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;
    }
  }
}
interestedparty333
  • 2,386
  • 1
  • 21
  • 35