2

I have an abstract class that has some constants that each child class will use. Each one of them is static, final and immutable.

public abstract class MyAbstract {

    //some private instance fields

    protected static final long LONG_ID = 1;
    protected static final String STRING_ID = "example_id";

    //some methods

}

I know that having protected static final is bad practice but what about protected static finals that are immutable? I know that I can make them public but I'd like to avoid doing so as the constants refer to specific ID's that user doesn't need to know.

Ava
  • 818
  • 10
  • 18
  • 2
    Wouldn't it be wiser to declare the constants in an interface? – arunken Aug 29 '19 at 06:33
  • 5
    Why is protected static final bad practice? – Kayaman Aug 29 '19 at 06:34
  • 1
    @Kenrig why would it be wiser? It would also make them implicitly public. – Kayaman Aug 29 '19 at 06:35
  • @Kayaman You can modify mutable objects this way in child classes. – Ava Aug 29 '19 at 06:37
  • 3
    @Ava you answered your own question: what is bad practice is not protected static final fields. What is bad practice is mutable constants. – JB Nizet Aug 29 '19 at 06:40
  • Note also that I have constants of different types, most of them are Strings but there are also some other types like longs and ints so enums don't solve it in elegant way. – Ava Aug 29 '19 at 06:41
  • 2
    @Ava that's the problem with mutable objects anyway, while static only makes it worse. Do it as you feel best, it's highly unlikely that a minor detail like this affects anything (besides eat into your development time). – Kayaman Aug 29 '19 at 06:41

1 Answers1

2

To answer your question in the title "What is the best practice of inheriting constants in Java?", my answer is: do not inherit them at all.

Inheritance has a special meaning and purpose in object oriented programming, and using inheritance just for convenience because you want to be able to access constants in a particular set of classes does not correspond to this meaning and purpose.

If you have constants that you want to be able to use in different classes, you can put the constants in a separate class. Make this class final and make the constructor private so that it can't be subclassed and instantiated:

package com.example;

public final class Constants {
    public static final long LONG_ID = 1L;
    public static final String STRING_ID = "example_id";

    // Private constructor, this class should not be instantiated
    private Constants() {
    }
}

Then, in a class where you want to use the constants, use import static:

import static com.example.Constants.LONG_ID;

public class Example {

    public void someMethod() {
        // Use the constant
        long id = LONG_ID;
        System.out.println(id);
    }
}

The advantage is that the class Example does not need to extend class Constants or implement an interface, so you do not need to misuse inheritance, while you still have the same convenience of being able to use the constants with concise syntax.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 1
    I'd not recommend to static-import a constant from `Constants` which looks to me as a global constants class and doesn't really belong to the domain of `MyAbstract` hierarchy. I'd rather use `GlobalConstants.ID`, `ModuleBConstants.ID`, but `ID` (as a statically-imported field from `MyAbstractConstants`) – Andrew Tobilko Aug 29 '19 at 07:57
  • @AndrewTobilko I agree, that's a valid choice - prefixing with the class name makes it more clear where the constant comes from than when you use a static import, at the cost of a little bit of convenience. Some people dislike static imports because it's not immediately obvious in the code where a statically imported constant or method comes from. – Jesper Aug 29 '19 at 08:07