14

I have an abstract class, for which I want all subclasses to define a constant, based on the implementation- it is mainly metadata about the class implementation.

In the superclass:

protected static final String OBJECT_NAME;
protected static final String OBJECT_DEF;

And then in the subclass:

protected static final String OBJECT_NAME = "awesome class";
protected static final String OBJECT_DEF = "an awesome class that is also great";

Is there a way to force implementations of a class to declare a constant?

pharma_joe
  • 591
  • 2
  • 9
  • 24
  • 1
    Probably worth noting that a constant with potentially different values is not a constant! So go with Peters answer. – TedTrippin Aug 13 '12 at 09:57

6 Answers6

12

You can force sub-class to define a method which can be a constant for that class.

protected abstract String objectName();
protected abstract String objectDef();

Note: if you have sub-class of your sub-classes, these might "forget" to override these methods.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 2
    The best you can get. Since the O.P. can't do exactly what he wants to do, this is certainly the best approach. – Zéychin Aug 10 '12 at 07:19
  • 1
    Thanks! Didn't think of this (obviously). There is no way to assure a sub-sub implementation of the static class implements these methods is there? – pharma_joe Aug 13 '12 at 00:29
1

This will not work that way. I would define these as abstract functions:

protected abstract String objectName();
protected abstract String objectDef();

And in the subclass:

private static final String OBJECT_NAME = "awesome class";
private static final String OBJECT_DEF = "bla";

protected String objectName(){
    return OBJECT_NAME;
}

protected String objectDef(){
    return OBJECT_DEF;
}

The methods are not static, but I think this is the closest you can get to what you want.

Dahaka
  • 507
  • 1
  • 4
  • 14
1

Might as well go for an interface as you don't have sensible defaults for the superclass:

interface HasObjectNameAndDef {
    public String getObjectName();
    public String getObjectDef(); 
}

Then have your actual classes implement the interface. You will get more flexible testing as a bonus.

David Soroko
  • 8,521
  • 2
  • 39
  • 51
1

Here is another approach. I like it because it is strict and lets us to place most of the code (includeing getters) into the parent class leaving its sublasses neat.

abstract class Parent {
    private final int age;
    private final String name;

    Parent(int age, String name) {
        this.age = age;
        this.name = name;
    }

    int getAge() {
        return age;
    }
}

class Child extends Parent {

    Child() {
        super(18, "John");
        // any other Child specific constructor logic
    }
}

class Main {
    public static void main(String[] args) {
        var child = new Child();
        System.out.println(child.getAge()); // Will print 18
    }
}

NOTE: Child does not inherit Parent's constructor and thus there is no danger of accidentally using the worng constructor when initializing Child.

Eerik Sven Puudist
  • 2,098
  • 2
  • 23
  • 42
0

No. You can't.

You even can't declare constant in your abstract superclass without assigning them concrete values. In other case you will get an error. You should initialize final fields during their declaration or in the class constructor.

You can declare abstract methods that will initialize your variables (but this will be more obfuscated). Like this:

protected String OBJECT_NAME = getObjectNameValue();

public abstract String getObjectNameValue();

But in such case your variables and methods should not be static. Because you cann't define static methods as abstract (look here for explanation).

Or you can use methods directly instead of variables as Peter Lawrey proposed, this will be more readable.

Community
  • 1
  • 1
dimas
  • 6,033
  • 36
  • 29
-1

I know what you're saying.

I for example, want to have an interface (which I am calling ExecutableList) have a contant String field called USER_FRIENDLY_NAME

public interface ExecutableList<T extends ExecutableList<T,E>,E> //This is type parameter
    extends List<E>,                                             //self referencing. Trust
            Comparable<E>,                                       //me, it has its uses.
{
  /** This would declare a constant but leave it to sub-interfaces/classes to define it. */
  abstract String USER_FRIENDLY_NAME;

  //Define the rest of your interface

}

Unfortunately, this is not possible in Java. When you declare a field in a Java interface, it implies the modifiers public, static, and final. A future change to the Java Programming Language MIGHT allow for abstract to be added, thus making the implied modifiers public abstract static final String USER_FRIENDLY_NAME; but while you could clearly define rules for this, the use of the word abstract would be confusing, as abstract and final are typically understood to define opposite meanings.

I'm crossing my fingers that a future version of Java will implement this. I have heard that private interface methods will be added in Java 9 (for use inbetween default methods) but no word yet on this addition to the language. There'd be a number of backwards compatability issues to consider first, I'm sure. If anyone from Oracle reads this, PLEASE LET US DECLARE CONSTANTS IN INTERFACES AND LET INHERITING CLASSES/INTERFACES DEFINE THEM!!!

In the meantime, your only option is to define a String getUserFriendlyName(); method in your interface or abstract class. Not as elegant and perhaps not as effecient, but you have no other option currently.

HesNotTheStig
  • 549
  • 1
  • 4
  • 9