views:

204

answers:

5

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?

A: 

I'm sure Java could have been designed like this. But it isn't.

tangens
+2  A: 

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
@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
+1  A: 

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
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
Thanks for pointing out :)
Felix Kling
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
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
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
Saying `protected String errorMsg;` does *not* enforce that you set the value in subclasses.
Laurence Gonsalves
@meriton: True, so it has to be set in the constructor.
Felix Kling
@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
@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
If having the value be null if you don't set it counts as "enforcement", then what would you call non-enforcement?
Laurence Gonsalves
@Laurence Gonsalves: Giving the field a value in the base class.
Felix Kling
A: 

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
Yea well ... this probably means that you are using reflection far to much!!
Stephen C
Sounds like a strange programming habit to me. Class.forName(..) smells like a design flaw.
Willi
Drew Wills
+5  A: 

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

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.

rsp
Haven't got an editor to try it here, but this was what I was going to post as well..
Tim
"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
And adding to @Stephen C's comment, "like when an abstract method is not implemented" is also an error, not a warning.
Laurence Gonsalves