Reflection API jenseits Class

Erzeugen von Instanzen

  • Instanzen werden über Constructor Objekte erzeugt
  • Man holt sich von Class den passenden Konstruktor mit Constructor<T> getConstructor(Class<?>... parameterTypes)
  • Neue Instanzen werden erzeugt mit newInstance(Object... params)
  • Mögliche Ausnahmen
    • SecurityException – Code darf keine Reflection machen
    • NoSuchMethodException – Es gibt den Konstruktor nicht
    • IllegalArgumentException – Argumente passen nicht
    • InstantiationException – Klasse ist abstrakt
    • IllegalAccessException – Konstruktor ist nicht public
    • InvocationTargetException – Konstruktor wirft selbst eine Exception

Beispiel: Instanz erzeugen

try {
    Constructor<Date> constructor
        = clazz.getConstructor(long.class);
    Object o = constructor.newInstance(222222222222L);
    System.out.println(o); // -> Sun Jan 16 01:23:42 CET 1977
} catch (SecurityException e) {
    // darf keine Reflection machen
} catch (NoSuchMethodException e) {
    // es gibt den Construktor nicht
} catch (IllegalArgumentException e) {
    // Argumente passen nicht
} catch (InstantiationException e) {
    // Klasse ist abstrakt
} catch (IllegalAccessException e) {
    // Konstruktor ist nicht public
} catch (InvocationTargetException e) {
    // Konstruktor wirft selbst eine Exception
}

Aufrufen von Methoden

  • Methoden werden über Method-Objekte gerufen
  • Man holt sich von Class die passende Methode mit Method getMethod(Class<?>... parameterTypes)
  • Die Methode wird aufgerufen mit invoke(Object o, Object... params)
  • Mögliche Ausnahmen
    • SecurityException – Code darf keine Reflection machen
    • NoSuchMethodException – Es gibt die Methode nicht
    • IllegalArgumentException – Argumente passen nicht
    • IllegalAccessException – Methode ist nicht public
    • InvocationTargetException – Methode wirft selbst eine Exception

Beispiel: Methoden aufrufen

Class<?> clazz = Integer.class;
Method m = clazz.getMethod("toHexString", int.class);
String result = (String) m.invoke(null, 255);
System.out.println(result); // -> ff

String s = "Hello ";
Class<?> clazz = s.getClass();
Method m = clazz.getMethod("concat", String.class);
Object result = m.invoke(s, "World!");
System.out.println(result); // -> Hello World!

Felder lesen und schreiben

  • Felder werden über Field Objekte manipuliert
  • Man holt sich von Class das passende Feld mit Field getField(String name)
  • Die Felder können dann mainpuliert werden mit get(Object o) und set(Object o, Object value)
  • Für gängige Datentypen gibt es Hilfsmethoden (setInt(...) etc.)
  • Mögliche Ausnahmen
    • SecurityException – Code darf keine Reflection machen
    • NoSuchFieldException – Es gibt das Feld nicht
    • IllegalArgumentException – Argumente passen nicht
    • IllegalAccessException – Feld ist nicht public

Beispiel: Felder manipulieren

Class<Integer> clazz = Integer.class;
Field field = clazz.getField("MAX_VALUE");
int value = field.getInt(null);
System.out.println(value); // -> 2147483647

Point point = new Point();
Class<?> clazz = point.getClass();
Field fieldX = clazz.getField("x");
Field fieldY = clazz.getField("y");
fieldX.setInt(point, 640);
fieldY.setInt(point, 480);
System.out.println(point); // -> java.awt.Point[x=640,y=480]

Arrays

  • Für Arrays gibt es keine eigenen Class Objekte, man benutzt das Objekt des Elementtyps
  • Arrays werden über die Klasse Array und deren statische Methoden manipuliert
    • Object newInstance(Class<?> componentType, int length)
    • Object newInstance(Class<?> componentType, int... dimensions)
    • int getLength(Object array)
    • Object get(Object array, int index)
    • void set(Object array, int index, Object value)

Beispiel: Arrays und Reflection

Class<String> elementTyp = String.class;

Object arrayInstanz = Array.newInstance(elementTyp, 4);

Array.set(arrayInstanz, 0, "Erster Eintrag");
Array.set(arrayInstanz, 1, "Zweiter Eintrag");
Array.set(arrayInstanz, 2, "Dritter Eintrag");
Array.set(arrayInstanz, 3, "Vierter Eintrag");

int length = Array.getLength(arrayInstanz);

for (int i = 0; i < length; i++) {
    Object element = Array.get(arrayInstanz, i);
    System.out.println(element);
}

Die dunkele Seite von Reflection

// Don't try this at home!!!
String immutable = "immutable String";
System.out.println(immutable);
System.out.println(immutable.hashCode());

Class<? extends String> clazz = immutable.getClass();
Field valueField = clazz.getDeclaredField("value");
valueField.setAccessible(true);

char[] chars = (char[]) valueField.get(immutable);
chars[0] = ' ';
chars[1] = ' ';

System.out.println(immutable);
System.out.println(immutable.hashCode());

Dieser Code zeigt, dass man mit Reflection Dinge tun kann, die normalerweise nicht möglich sind, z. B. den inneren Zustand eines Strings ändern. Solche Konstrukte sind ausgesprochen gefährlich und können bis zum Absturz der VM führen.


Copyright © 2025 Thomas Smits