lowq
lowq

Reputation: 628

Final field inheritance in java

Is it possible to have a given subclass initialize static final fields in its superclass? Essentially I would like for the subclass to configure required class-wide variables. Unfortunately, the abstract keyword doesn't exactly work with fields..

Upvotes: 1

Views: 1684

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1499860

No - how would you expect it to work if there were two subclasses which tried to do the same thing? If you've got static final fields, they must be initialized by the class which declares them.

If you're trying to use static fields and inheritance together, that's usually a sign that something's wrong to start with, to be honest - they're two concepts which generally don't play well together. People often try to "fake" inheritance with static methods etc, and it usually ends badly - this sounds like a variation on that theme.

If you can describe your broader picture, we may be able to help you more. I would urge you to avoid statics in general for the sake of testability, by the way. They're fine for genuine constants, but if it's anything like configuration, it's nicer to pass in relevant settings when constructing an object (IMO).

EDIT: I can see four options which would model your situation better:

  1. Use annotations: see True Soft's answer
  2. Make maxHealth a method, so you can ask any player what their maximum health is - that's then polymorphic, so can be overridden in each class
  3. Model Player and PlayerClass separately:

    public class Player {
        private final PlayerClass playerClass;
        private int health; // etc
    }
    
    public class PlayerClass {
        private final int maxHealth; //etc
    }
    

    That way you can have inheritance at the "player class" level, but you don't have to - you could create several PlayerClass instances which behave the same way, but have different stats... or you could subclass PlayerClass to give custom behaviour. At that point you may not need different subclasses of Player at all.

  4. The same as idea 3, but using an enum:

    public enum PlayerClass {
        ELF(10), DWARF(9), HUMAN(5);
    
        private final int maxHealth;
        private PlayerClass(int maxHealth) {
            this.maxHealth = maxHealth;
        }
    }
    

Personally my preference would be the final option, I suspect. You can still override behaviour, but you have a fixed set of possible classes - which probably models your game reasonably accurately.

Upvotes: 5

True Soft
True Soft

Reputation: 8786

Regarding Jon Skeet's answer, I don't think it's that bad "If you're trying to use static fields and inheritance together". I suggest you to use annotations:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface AValue {
    /**
     * @return something final that is "static" (attached to a class), 
     * but also "abstract" (looks that it be changed in the subclasses)
     */
    String value();
}

@AValue("A default value") // you can ommit this, but all subclasses should add the annotation (so the method from Utils work OK)
abstract class A { }

@AValue("Value for class B")
class B extends A { }

@AValue("Value for class C")
class C extends A { }

class Utils {
    static String getValueOfClass(Class<? extends A> clazz) {
        return clazz.getAnnotation(AValue.class).value();
    }
}

Upvotes: 1

Related Questions