Search code examples
javaabstract-class

How to initialize a generic value in an abstract class?


I have a generic abstract class with a generic value, which I would like to mark final:

public abstract class Value<T>
{
  final T value;

  static class StringValue extends Value<String>
  {
    StringValue (String value)
    {
      this.value = value + value;
    }
  }

  static class IntegerValue extends Value<Integer>
  {
    IntegerValue (Integer value)
    {
      this.value = value * value;
    }
  }

  public static void main (String[] args)
  {
    StringValue  s = new StringValue ("Hello");
    IntegerValue i = new IntegerValue (42);
  }
}

But this does not work:

Value.java:9: error: cannot assign a value to final variable value
      this.value = value;
          ^
Value.java:17: error: cannot assign a value to final variable value
      this.value = value;
          ^
2 errors

The compiler forces me to initialize the generic value in the abstract class, but this does not make any sense, because the value is generic and can only be initialized in the derived classes.

How to work around this problem?


Solution

  • You need to either assign a final variable when declaring it or in the constructor of the class.

    It does not work with the constructor of child classes.

    However, the abstract class can have a constructor with the generic type as a parameter and use that.

    The child classes can then call the parent constructor:

    public abstract class Value<T>
    {
      final T value;
      protected Value(T value){
        this.value=value;
      }
    
      static class StringValue extends Value<String>
      {
        StringValue (String value)
        {
          super(value + value);
        }
      }
    
      static class IntegerValue extends Value<Integer>
      {
        IntegerValue (Integer value)
        {
          super(value * value);
        }
      }
    
      public static void main (String[] args)
      {
        StringValue  s = new StringValue ("Hello");
        IntegerValue i = new IntegerValue (42);
      }
    }