Reflection (Java)

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen

Reflection in Java ist eine Möglichkeit, Informationen über Klassen, Methoden und andere Sprachelemente zu erhalten, ohne diese Elemente während dem Programmieren zu kennen.

Eine kleine Auswahl von Informationen:

Diese Informationen können auch dazu verwendet werden, Objekte einer bestimmten Klasse herzustellen, die Methoden des Objektes aufzurufen, oder Felder des Objektes abzuändern. Der Typ des Objektes muss wiederum nicht im vornherein bekannt sein.

Arbeiten mit Reflection

Um mit Reflection zu arbeiten, benötigt man ein Class-Objekt desjenigen Typen, mit dem man arbeiten will. Dieses Objekt erhält man üblicherweise auf einem der folgenden Wege:

  • Mittels dem Syntax "x.class", wobei "x" ein beliebiger Typ sein kann.
Class<?> classString = String.class;
Class<?> classInt = int.class;
Class<?> classFloatArray = float[].class;
  • Mit der Methode "getClass", welche jedes Objekt besitzt.
Object unknown = ...
Class<?> classUnknown = unknown.getClass();
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> classFrame = loader.loadClass( "javax.swing.JFrame" );

Zugriff auf Informationen

Die Klasse Class bietet verschiedene Methoden mehr über die dargestellte Klasse herauszufinden. Das geht von dem Namen der Klasse ("getName"), über die Klasse von der geerbt wurde ("getSuperclass") bis zu allen Methoden ("getDeclaredMethods"), Konstruktoren ("getConstructors") und Feldern ("getFields").

Über einzelne Felder, Methoden, ... lassen sich dann wiederum zusätzliche Informationen abrufen, z.B. die Argumente eines Konstruktors.

Objekte generieren

Besitzt man erstmal die Klasse, will man meist auch ein Objekt dieser Klasse haben.

Dazu gibt es zwei einfache Wege:

  • Direkt über die Methode "newInstance" von Class kann ein Objekt erzeugt werden. Das entspricht genau dem Verhalten, wie wenn man den Defaultkonstruktor aufrufen würde. Wenn kein solcher Konstruktor vorhanden ist, wird eine Exception geworfen.
  • Über ein Constructor-Objekt, indem die Methode "newInstance" mit passenden Argumenten aufgerufen wird.

Im folgenden Beispiel wird ein Punkt erzeugt, und ausgegeben:

Class<?> point = Class.forName( "java.awt.Point" );
Constructor<?> constructor = point.getConstructor( 
  new Class[]{ int.class, int.class });
Object object = constructor.newInstance( new Object[]{ 45, 97 });

System.out.println( object );

Aufrufe tätigen

Mit Reflection kann man auch Methoden aufrufen oder Felder ändern.

  • Anstelle des normalen Methodenaufrufes "object.x( y, z )" benutzt man das Method-Objekt, welches die Methode "x" darstellt, und ruft "x.invoke( object, x, y )" auf.
  • Anstelle einer Zuweisung "object.x = y" benutzt man das Field-Objekt, welches "x" darstellt, und ruft "x.set( object, y )" auf.

Beispiele

Restriktionen aushebeln

Das folgende Beispiel benutzt Reflection um auf den, eigentlich geschützten, char-Array eines Strings zuzugreiffen.

import java.lang.reflect.Field;

public class Evil {
    public static void main( String[] args ) throws Exception{
        // Die Ausgabe dieses Programmes ist...
        System.out.println( "Hallo Welt" );
        // ... jedenfalls nicht "Hallo Welt"
    }
    
    static{
        try{
            // Repräsentation der String-Klasse abrufen
            Class<String> clazz = String.class;
            
            String object = "Hallo Welt";
            String text = "Ich bin böse!";

            // Zugriff auf die Felder "value" und "count" erlangen
            Field value = clazz.getDeclaredField( "value" );
            Field count = clazz.getDeclaredField( "count" );

            // Die Sichtbarkeit der Felder von private auf public erhöhen
            value.setAccessible( true );
            count.setAccessible( true );

            // Den Feldern neue Werte zuweisen
            value.set( object, text.toCharArray() );
            count.setInt( object, text.length() );
        }
        catch( Exception ex ){
            ex.printStackTrace();
        }
    }
}

Objekt herstellen und Methoden aufrufen

Dieses Beispiel zeigt, wie eine Klasse, von der man nur den Namen kennt, und die garantiert noch nicht im System existiert, geladen wird. Danach wird eine Instanz dieser Klasse angelegt, und eine Methode aufgerufen.

package hidden;

import java.lang.reflect.Method;

public class Hidden {
    public static void main( String[] args ) throws Exception{
        Loader loader = new Loader();
        Class<?> clazz = loader.loadClass( "hidden.Riddle" );
        
        Object object = clazz.newInstance();
        Method run = clazz.getMethod( "run", new Class[0] );
        run.invoke( object, new Object[0] );
    }
    
    private static class Loader extends ClassLoader{
        @Override
        protected Class<?> findClass( String name ) throws ClassNotFoundException {
            if( name.equals( "hidden.Riddle" )){
                return defineClass( "hidden.Riddle", CODE, 0, CODE.length );
            }
            else
                return super.findClass( name );
        }
    }
    
    public static final byte[] CODE = {
        -54, -2, -70, -66, 0, 0, 0, 49, 0, 78, 7, 
        0, 2, 1, 0, 13, 104, 105, 100, 100, 101, 110, 
        47, 82, 105, 100, 100, 108, 101, 7, 0, 4, 1, 
        0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 
        47, 79, 98, 106, 101, 99, 116, 1, 0, 5, 118, 
        97, 108, 117, 101, 1, 0, 1, 73, 1, 0, 6, 
        60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 
        86, 1, 0, 4, 67, 111, 100, 101, 10, 0, 3, 
        0, 11, 12, 0, 7, 0, 8, 10, 0, 13, 0, 
        15, 7, 0, 14, 1, 0, 14, 106, 97, 118, 97, 
        47, 108, 97, 110, 103, 47, 77, 97, 116, 104, 12, 
        0, 16, 0, 17, 1, 0, 6, 114, 97, 110, 100, 
        111, 109, 1, 0, 3, 40, 41, 68, 6, 64, 89, 
        0, 0, 0, 0, 0, 0, 9, 0, 1, 0, 21, 
        12, 0, 5, 0, 6, 1, 0, 15, 76, 105, 110, 
        101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 
        101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 
        114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 
        1, 0, 4, 116, 104, 105, 115, 1, 0, 15, 76, 
        104, 105, 100, 100, 101, 110, 47, 82, 105, 100, 100, 
        108, 101, 59, 1, 0, 3, 114, 117, 110, 7, 0, 
        28, 1, 0, 17, 106, 97, 118, 97, 47, 117, 116, 
        105, 108, 47, 83, 99, 97, 110, 110, 101, 114, 9, 
        0, 30, 0, 32, 7, 0, 31, 1, 0, 16, 106, 
        97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 121, 
        115, 116, 101, 109, 12, 0, 33, 0, 34, 1, 0, 
        2, 105, 110, 1, 0, 21, 76, 106, 97, 118, 97, 
        47, 105, 111, 47, 73, 110, 112, 117, 116, 83, 116, 
        114, 101, 97, 109, 59, 10, 0, 27, 0, 36, 12, 
        0, 7, 0, 37, 1, 0, 24, 40, 76, 106, 97, 
        118, 97, 47, 105, 111, 47, 73, 110, 112, 117, 116, 
        83, 116, 114, 101, 97, 109, 59, 41, 86, 9, 0, 
        30, 0, 39, 12, 0, 40, 0, 41, 1, 0, 3, 
        111, 117, 116, 1, 0, 21, 76, 106, 97, 118, 97, 
        47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 
        114, 101, 97, 109, 59, 8, 0, 43, 1, 0, 38, 
        71, 105, 98, 32, 101, 105, 110, 101, 32, 90, 97, 
        104, 108, 32, 122, 119, 105, 115, 99, 104, 101, 110, 
        32, 48, 32, 117, 110, 100, 32, 49, 48, 48, 32, 
        101, 105, 110, 58, 32, 10, 0, 45, 0, 47, 7, 
        0, 46, 1, 0, 19, 106, 97, 118, 97, 47, 105, 
        111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 
        97, 109, 12, 0, 48, 0, 49, 1, 0, 5, 112, 
        114, 105, 110, 116, 1, 0, 21, 40, 76, 106, 97, 
        118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 
        105, 110, 103, 59, 41, 86, 10, 0, 27, 0, 51, 
        12, 0, 52, 0, 53, 1, 0, 10, 104, 97, 115, 
        78, 101, 120, 116, 73, 110, 116, 1, 0, 3, 40, 
        41, 90, 10, 0, 27, 0, 55, 12, 0, 56, 0, 
        57, 1, 0, 7, 110, 101, 120, 116, 73, 110, 116, 
        1, 0, 3, 40, 41, 73, 8, 0, 59, 1, 0, 
        7, 82, 105, 99, 104, 116, 105, 103, 10, 0, 45, 
        0, 61, 12, 0, 62, 0, 49, 1, 0, 7, 112, 
        114, 105, 110, 116, 108, 110, 8, 0, 64, 1, 0, 
        16, 70, 97, 108, 115, 99, 104, 44, 32, 122, 117, 
        32, 107, 108, 101, 105, 110, 8, 0, 66, 1, 0, 
        16, 70, 97, 108, 115, 99, 104, 44, 32, 122, 117, 
        32, 103, 114, 111, 115, 115, 8, 0, 68, 1, 0, 
        24, 68, 97, 115, 32, 115, 111, 108, 108, 32, 101, 
        105, 110, 101, 32, 90, 97, 104, 108, 32, 115, 101, 
        105, 110, 63, 10, 0, 27, 0, 70, 12, 0, 71, 
        0, 72, 1, 0, 4, 110, 101, 120, 116, 1, 0, 
        20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 
        110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 
        0, 1, 115, 1, 0, 19, 76, 106, 97, 118, 97, 
        47, 117, 116, 105, 108, 47, 83, 99, 97, 110, 110, 
        101, 114, 59, 1, 0, 5, 99, 104, 101, 99, 107, 
        1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 
        108, 101, 1, 0, 11, 82, 105, 100, 100, 108, 101, 
        46, 106, 97, 118, 97, 0, 33, 0, 1, 0, 3, 
        0, 0, 0, 1, 0, 2, 0, 5, 0, 6, 0, 
        0, 0, 2, 0, 1, 0, 7, 0, 8, 0, 1, 
        0, 9, 0, 0, 0, 67, 0, 5, 0, 1, 0, 
        0, 0, 17, 42, -73, 0, 10, 42, -72, 0, 12, 
        20, 0, 18, 107, -114, -75, 0, 20, -79, 0, 0, 
        0, 2, 0, 22, 0, 0, 0, 14, 0, 3, 0, 
        0, 0, 5, 0, 4, 0, 6, 0, 16, 0, 5, 
        0, 23, 0, 0, 0, 12, 0, 1, 0, 0, 0, 
        17, 0, 24, 0, 25, 0, 0, 0, 1, 0, 26, 
        0, 8, 0, 1, 0, 9, 0, 0, 0, -33, 0, 
        3, 0, 3, 0, 0, 0, 105, -69, 0, 27, 89, 
        -78, 0, 29, -73, 0, 35, 76, -78, 0, 38, 18, 
        42, -74, 0, 44, 43, -74, 0, 50, -103, 0, 65, 
        43, -74, 0, 54, 61, 28, 42, -76, 0, 20, -96, 
        0, 14, -78, 0, 38, 18, 58, -74, 0, 60, -89, 
        0, 57, 28, 42, -76, 0, 20, -94, 0, 14, -78, 
        0, 38, 18, 63, -74, 0, 60, -89, -1, -55, 28, 
        42, -76, 0, 20, -92, -1, -63, -78, 0, 38, 18, 
        65, -74, 0, 60, -89, -1, -74, -78, 0, 38, 18, 
        67, -74, 0, 60, 43, -74, 0, 69, 87, -89, -1, 
        -90, -79, 0, 0, 0, 2, 0, 22, 0, 0, 0, 
        62, 0, 15, 0, 0, 0, 9, 0, 11, 0, 11, 
        0, 19, 0, 12, 0, 26, 0, 13, 0, 31, 0, 
        14, 0, 39, 0, 15, 0, 47, 0, 16, 0, 50, 
        0, 18, 0, 58, 0, 19, 0, 69, 0, 21, 0, 
        77, 0, 22, 0, 88, 0, 26, 0, 96, 0, 27, 
        0, 101, 0, 30, 0, 104, 0, 31, 0, 23, 0, 
        0, 0, 32, 0, 3, 0, 0, 0, 105, 0, 24, 
        0, 25, 0, 0, 0, 11, 0, 94, 0, 73, 0, 
        74, 0, 1, 0, 31, 0, 57, 0, 75, 0, 6, 
        0, 2, 0, 1, 0, 76, 0, 0, 0, 2, 0, 77 };
}