Freitag, 23. November 2012

Instance initializations in abstract Java classes

Instance initializations are rarely seen in Java code but they allow funny things together with abstract classes. Class initializations are widely used and are written by enclosing the code block with single curly brackets. Instance initializations are written in the same way but with two curly brackets. When used in an abstract class the initialization code gets executed in the scope of the derived class but without the need to specify any constructor and without the need to call any parent constructor with super. Furthermore it is possible to call abstract methods in the initialization block. By this it is possible to force an initialization with some kind of default logic but without forcing the derived class to use this default logic. The following example illustrates this.
// -*- compile-command: "javac custom.java && java custom"; -*-

class custom
{
    abstract class A
    {
        final String name;
        {{ name = calc_name(); }}

        protected String calc_name() {
            return getClass().getName();
        }
    }
    
    class B extends A
    {
    }

    class C extends A
    {
        protected String calc_name() { return "C"; }
    }

    void run ()
    {
        B b = new B();
        C c = new C();
        System.out.println (b.name);  // -> custom$B
        System.out.println (c.name);  // -> C
    }

    public static void main (String argv[])
    {
        custom x = new custom();
        x.run();
    }
}
The same thing will not work in static contexts, because Java lacks any generic syntax like self in PHP to get the name of the current class other than writing an exact class name directly into the code. Calling A.class.getName() in the abstract class A will never return B in the class B derived from the abstract class A.

Keine Kommentare: