Final Classes

A final class is a class that does not allow itself to be inherited by another class. Final classes mark endpoints in the inheritance tree. There are two ways to make a class final. The first is to use the keyword final in the class declaration:

public final class SomeClass {
 // . . . Class contents
}


The second way to make a class final is to declare all of its constructors as private:

public class SomeClass {
 public final static SOME_INSTANCE = new SomeClass(5);
 private SomeClass(final int value) {
 }
}


When you give all constructors private visibility, you are implicitly declaring the class as final; often, this is not the intended result. In fact, it is the omission of the keyword final on the class declaration that should alert you to the fact that something is wrong. The class above may very well need to be final, in which case you should always specifically use the keyword final in the class declaration. If you don't follow this rule, you could end up causing some devious problems. To find an example of these problems, you need to look no further than the JDK itself. In the java.beans package, you will find a class called Introspector (see ). Take a look at its single constructor in Example 2-17.[2]

[2] J2SDK source code. © 2002 by Oracle.

Example 2-17. The java.beans.Introspector source snippets
public class Introspector {
 // . . . snip . . . private Introspector(Class beanClass, Class stopClass, int flags)
 throws IntrospectionException {
 // . . . snip . . . }
}


The constructor for the Introspector class is private. I noticed this while studying this class. My goal was to extend the Introspector and create a class that is more feature-rich than Introspector itself. Unfortunately, since the only constructor of the class is private, it is impossible to extend this class. In the case of the Introspector class, there is no reason that the class should be final. The Introspector class is a good example of how implicit final classes can cause problems. Most singleton classes shouldn't be declared as final. You never know what other features your class's user will dream up. However, since singleton classes need to be protected from external instantiation, you can't make the constructor public. The solution to the problem is a protected constructor, as shown in Example 2-18.

Example 2-18. An extensible singleton
package oracle.hcj.finalstory;
public class Singleton {
 private static final Logger LOGGER = Logger.getLogger(Singleton.class);
 public static Singleton instance = null;
 private final String[] params;
 public static void init(final String[] params) {
 // . . . do some initialization . . . instance = new Singleton(params);
 }
 protected Singleton(final String[] params) {
 this.params = params;
 if (LOGGER.isDebugEnabled( )) {
 LOGGER.debug(Arrays.asList(this.params).toString( ));
 }
 }
}


Since this singleton class has a protected constructor instead of a private constructor, you can extend its functionality while protecting it against construction by the user. This will allow you to extend the singleton, as shown in Example 2-19.

Example 2-19. An extension of a singleton
package oracle.hcj.finalstory;
public class ExtendedSingleton extends Singleton {
 private final static int DEFAULT_VALUE = 5;
 private final int value;
 public static void init(final String[] params) {
 instance = new ExtendedSingleton(params, DEFAULT_VALUE);
 }
 public static void init(final String[] params, final int value) {
 instance = new ExtendedSingleton(params, value);
 }
 protected ExtendedSingleton(final String[] params, final int value) {
 super(params);
 this.value = value;
 }
}


The protected constructor technique is not limited to classes with instance variables and methods. A protected constructor should be declared for classes that are entirely static in nature. Although these classes have no other instance members, it would be possible, if a bit pointless, to instantiate them. Preventing this instantiation while providing extensibility is definitely an asset to the development process. There are rare circumstances when a class should be made final. One example is the concept of the constant object class, which we will discuss in . However, making classes implicitly final is never a good thing; if you want to make a class final, come right out a declare it with the class declaration.

      
Comments