Statische Initialisierung einer Schnittstelle

Eigentlich kann man die Variablen einer Schnittstellen nicht dynamisch initialisieren. Mit einem inneren-Klassen-Trick lässt sich das jedoch bewerkstelligen.

Standardmäßig wird die Initialisierung von Schnittstellen nicht von der Sprache Java unterstützt, doch die virtuelle Maschine kennt eine solche Möglichkeit. Diese jedoch in Java Bytecode abzubilden wird dem Aufwand nicht gerecht.

Beispiel: Für die nachfolgende fehlerhafte Schnittstelle müssen wir eine neue Variante suchen.

public interface Numbers
{
  int ONE = 1;
  int TWO = 2;
  int THREE = 3;

  public static final Hashtable names = new Hashtable();

  static {		
  ^
// Hier gibt's den Compilerfehler
// "Interfaces can't have static initializers."

    names.put( new Integer(ONE), "one" );
    names.put( new Integer(TWO), "two" );
    names.put( new Integer(THREE), "three" );
  }
}

Es wäre nun angenehm, wenn die Hashtabelle vorher initialisiert werden könnte. Denn hierbei handelt es sich ja im weitesten Sinne auch um eine Konstante. Der Trick, wie dieses Problem gelöst werden kann, liegt in der Einführung einer inneren Klasse, die wir HashInit nennen wollen. Innerhalb dieser Klasse platzieren wir nun den Initialisierungsblock. Anschließend muss nur noch eine Dummy-Variable gesetzt werden, damit der Initialisierungsblock der inneren Klasse auch ausgeführt wird. Dazu definieren wir eine Variable hashInit. Sie ist static und final, also somit eine echte Konstante. Leider können Variablen innerhalb von Schnittstellen nicht privat sein, sodass sie unglücklicherweise von außen zugänglich ist.

import java.util.Hashtable;

interface Numbers
{
  int ONE = 1;
  int TWO = 2;
  int THREE = 3;
 
  Hashtable names = new Hashtable();

  Object hashInit = new HashInit();

  static final class HashInit
  { 
    static
    {
      names.put( new Integer(ONE), "one" );
      names.put( new Integer(TWO), "two" );
      names.put( new Integer(THREE), "three" );
    }
  }
}

Innerhalb von static{} lässt sich auf die Hashtable der Schnittstelle zugreifen und somit lassen sich auch die Werte eintragen. Ohne die Erzeugung des Objekts hashInit geht es nicht, denn andernfalls würde die Klasse HashInit nicht initialisiert werden. Das Programm kann nun alle Elemente wie folgt nutzen:

class UseNumbers implements Numbers
{
  public static void main( String args[] )
  {
    System.out.println(
      "THREE is " + names.get( new Integer(THREE) ) );
  }
}