Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Introduction à la réflexion Java

Définition de méthodes génériques Coder un moteur de sérialisation



Accès rapide :
La vidéo
Qu'est-ce que la réflexion ?
Récupérer les méta-données d'un type via la classe java.lang.Class
Lister les attributs d'une classe
Lister les attributs publics de la classe
Lister uniquement les attributs déclarés dans la classe
Lister l'ensemble des attributs disponibles sur la classe
Lister les méthodes d'une classe
Les principales possibilités proposées
Exemple de parcours de toutes les méthodes exposées par une classe
Lister les constructeurs d'une classe
Les principales possibilités proposées
Exemple de parcours de tous les constructeurs (publics ou non) exposés par une classe
Manipulation des types sur lesquels est basée notre classe
Lister la hiérarchie d'héritage
Lister les interfaces implémentées par notre classe
La réflexion dans le cadre de l'écriture de jeux de tests unitaires
Accès à un attribut privé
Accès à une méthode privée

La vidéo

Cette vidéo vous montre comment utiliser le moteur de réflexion Java (accessible dans le package java.lang.reflect) pour obtenir des informations descriptives sur vos types de données.


Introduction à la réflexion Java

Qu'est-ce que la réflexion ?

La réflexion est un concept objets permettant d'avoir accès à la structure interne de vos types. Certains langages objets ne supportent pas nativement la réflexion : c'est notamment le cas de C++. Cela est dû au fait que C++ supprime la « table des symboles » de l'exécutable produit. Cette table des symboles contient notamment la définition de tous les membres de la classe et est utile durant la phase d'édition des liens (aussi appelée « link »).

En Java, la table des symboles est requise au bon fonctionnement de votre programme, notamment à cause du fait que l'édition de liens est réalisée pendant l'exécution de votre programme (au chargement du code de la classe par le « Class Loader »). La réflexion permet donc d'accéder aux informations stockées dans cette table des symboles.

Il y a un point négatif au fait que Java propose la réflexion : il est très facile de décompiler un code Java. De nombreux décompilateurs vous sont proposés : jad, ... Si vous souhaitez vous prémunir de la décompilation, c'est compliqué en Java. Au mieux vous pouvez obfusquer (offusquer, si vous préférez) votre code Java (brouiller certains éléments de la table des symboles).

A contrario, la réflexion permet de nombreuses possibilités intéressantes du langage Java : sérialisation, garbage collector, ... Nous allons d'ailleurs en étudier certaines dans les chapitres suivants.

Le support de réflexion Java est proposé par la classe java.lang.Class et le package java.lang.reflect (reflect pour reflection, en anglais).

Récupérer les méta-données d'un type via la classe java.lang.Class

Le point d'entrée sur le moteur de réflexion consiste à récupérer les méta-données (les données descriptives) d'un type Java : ces méta-données seront stockées dans une instance de type java.lang.Class. Deux possibilités sont disponibles pour récupérer des méta-données : soit à partir d'une instance (avec la méthode getClass()), soit à partir d'un type Java, via un pseudo-attribut statique. Voici un exemple de code montrant ces deux possibilités.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
public class TestReflection {
    
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<TestReflection> metadata = TestReflection.class;
        
        // Récupération des méta-données à partir d'une instance.
        TestReflection object = new TestReflection();
        Class<? extends TestReflection> metadata2 = object.getClass();
        
        // Dans les deux cas, nous avons les mêmes informations
        System.out.println( metadata == metadata2 );
        
    }
    
}
Récupération de méta-données
l'opérateur == utilisé entre deux instances Java compare les pointeurs. La valeur true indique donc que c'est la même instance qui est retournée dans les deux cas.
la classe java.lang.Class est générique. L'utilisation de la syntaxe <? extends TestReflection> permet d'éviter un warning.

Lister les attributs d'une classe

Nous allons maintenant chercher à travailler sur les définitions d'attributs d'une classe. Pour autant, vous avez deux possibilités : soit vous cherchez à récupérer uniquement les attributs publics d'une classe (y compris ceux hérités), soit vous cherchez à travailler que sur les attributs de la classe considérée (quel que soit le niveau de visibilité considéré).

Lister les attributs publics de la classe

L'exemple de code suivant permet d'afficher des informations sur l'ensemble des attributs publics d'une classe (y compris ceux hérités des classes parentes). Ces informations sont acquises grâce à la méthode getFields().

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
import java.lang.reflect.Field;
import java.util.Date;

class Base {
    public int first;
    private int second;
}

public class TestReflection extends Base {

    private int aNumericValue;
    protected String aString;
    double aPrice;      // Visibilité "package" par défaut
    public Date aDate;
    
    
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<TestReflection> metadata = TestReflection.class;
        
        // On récupère les attributs publics disponibles à partir de la classe
        // (et y compris dans les classes parentes : Base et Object).
        Field [] attributes = metadata.getFields();
        
        // On affiche des informations sur ces attributs publics.
        for( Field attribute : attributes ) {
            System.out.printf( 
                    "%s of type %s (isPrimitive: %b)\n",
                    attribute.getName(), 
                    attribute.getType().getName(),
                    attribute.getType().isPrimitive()
            );
        }
        
    }
    
}
Exemple de récupération d'informations sur les attributs publics d'une classe
la méthode isPrimitive permet de savoir si le type manipulé est un type élémentaire du langage ou si c'est un type objet (une instance).

Voici les résultats produits par cet exemple de code :

aDate of type java.util.Date (isPrimitive: false)
first of type int (isPrimitive: true)

Si vous souhaitez retrouver les données descriptives d'un attribut public particulier, vous pouvez aussi utiliser la méthode Class.getField( String fieldName ). Voici un petit extrait de code.

 1 
 2 
Class<TestReflection> metadata = TestReflection.class;
Field field = metadata.getField( "aDate" );
Accès aux méta-données d'un attribut public.

Lister uniquement les attributs déclarés dans la classe

L'exemple de code suivant ne liste que, et uniquement que, les attributs déclarés dans la classe considérée. Les attributs définis dans une classe parentes, (quelles que soient leurs visibilités) ne seront pas considérés. Ces informations sont acquises grâce à la méthode getDeclaredFields().

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
import java.lang.reflect.Field;
import java.util.Date;

class Base {
    public int first;
    private int second;
}

public class TestReflection extends Base {

    private int aNumericValue;
    protected String aString;
    double aPrice;      // Visibilité package par défaut
    public Date aDate;
    
    
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<TestReflection> metadata = TestReflection.class;
        
        // On récupère tous les attributs déclarés dans la classe
        Field [] attributes = metadata.getDeclaredFields();
        
        // On affiche des informations sur les attributs.
        for( Field attribute : attributes ) {
            System.out.printf( 
                    "%s of type %s (isPrimitive: %b)\n",
                    attribute.getName(), 
                    attribute.getType().getName(),
                    attribute.getType().isPrimitive()
            );
        }
        
    }
    
}
Exemple de récupération d'informations sur les attributs déclarés dans la classe

Voici les résultats produits par cet exemple de code :

aNumericValue of type int (isPrimitive: true)
aString of type java.lang.String (isPrimitive: false)
aPrice of type double (isPrimitive: true)
aDate of type java.util.Date (isPrimitive: false)

Si vous souhaitez retrouver les données descriptives d'un attribut particulier, vous pouvez aussi utiliser la méthode Class.getDeclaredField( String fieldName ). Voici un petit extrait de code.

 1 
 2 
Class<TestReflection> metadata = TestReflection.class;
Field field = metadata.getDeclaredField( "aDate" );
Accès aux méta-données d'un attribut quelconque de la classe

Lister l'ensemble des attributs disponibles sur la classe

Ce nouvel exemple vous montre comment lister l'ensemble des attributs disponibles sur la classe (y compris ceux définis sur les classes dérivées). La méthode Class.getSuperclass() permet de récupérer les méta-données de la classe parente. En effectuant une remonter récursive dans les méta-données parentes, on peut traiter l'ensemble des attributs existants.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;

class Base {
    public int first;
    private int second;
}

public class TestReflection extends Base {

    private int aNumericValue;
    protected String aString;
    double aPrice;      // Visibilité package par défaut
    public Date aDate;
    
    
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<?> metadata = TestReflection.class;
        
        while ( true ) {
            // On affiche le type en cours d'analyse
            System.out.println( metadata.getName() );
            
            // On récupère les attributs déclarés dans le type courant.
            Field [] attributes = metadata.getDeclaredFields();
            
            // On affiche des informations sur les attributs du type.
            for( Field attribute : attributes ) {
                Class<?> attributeMetadata = attribute.getType(); 
            
                System.out.printf( 
                        "\t%-10s %s of type %s (isPrimitive: %b)\n",
                        Modifier.toString( attribute.getModifiers() ),
                        attribute.getName(), 
                        attributeMetadata.getName(),
                        attributeMetadata.isPrimitive()
                );
            }
            
            // On remonte sur le type parent, s'il y en a un.
            metadata = metadata.getSuperclass();
            if ( metadata == null ) break;
        }
    }
    
}
On liste l'ensemble des attributs disponibles sur la classe

Et voici les résultats produits par cet exemple de code :

TestReflection
    private    aNumericValue of type int (isPrimitive: true)
    protected  aString of type java.lang.String (isPrimitive: false)
               aPrice of type double (isPrimitive: true)
    public     aDate of type java.util.Date (isPrimitive: false)
Base
    public     first of type int (isPrimitive: true)
    private    second of type int (isPrimitive: true)
java.lang.Object

Lister les méthodes d'une classe

De la même manière que nous venons de lister les méta-données des attributs de la classe, vous pouvez parcourir l'ensemble des méthodes d'un type et en manipuler leurs données descriptives. Ces informations seront stockées dans des instances de type java.lang.reflect.Method. La méthode Class.getMethods() renvoie l'ensemble des méthodes publiques (y compris celles des classes parentes) alors de la méthode Class.getDeclaredMethods() renvoie l'ensemble des méthodes contenues uniquement dans cette classe (quelles ques soient leurs visibilités).

Les principales possibilités proposées

Voici les principales méthodes de la classe java.lang.Class permettant de retrouver des données descriptives (méta-données) à propos des méthodes d'un type.

Exemple de parcours de toutes les méthodes exposées par une classe

L'exemple de code proposé ci-dessous parcourt l'ensemble de méthodes directement définies dans la classe. On y retrouve des méthodes statiques ou non et avec une visibilité quelconque (public, private, ...).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
import java.lang.reflect.Method;


public class TestReflection {

    public void publicMethod() {}
    private void privateMethod() {}
    
    public static void publicStaticMethod() {}
    private static void privateStaticMethod() {}
    
    
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<?> metadata = TestReflection.class;
        
        // On récupère les méthodes déclarées dans le type courant
        Method [] methods = metadata.getDeclaredMethods();
        
        // On affiche des informations sur les méthodes de la classe
        for( Method method : methods ) {
            System.out.println( method.getName() );
        }
        
    }
    
}
Analyse des méthodes de la classe

Et voici les résultats produits par cet exemple de code :

main
publicStaticMethod
publicMethod
privateMethod
privateStaticMethod
la méthode main étant définie dans la classe traitée par cet exemple, il est normal de la retrouver dans les résultats produits.

Lister les constructeurs d'une classe

Dans le cadre de l'analyse des constructeurs, il est important de se rappeler qu'ils ne s'héritent pas. Il est donc impossible, via une instance de méta-données de retrouver des informations sur les constructeurs déclarés dans les types parents.

Les données descriptives d'un constructeur seront contenues dans une instance Java de type java.lang.refect.Constructor et il s'agit d'un type générique.

Les principales possibilités proposées

Voici les principales méthodes de la classe java.lang.Class permettant de retrouver des données descriptives (méta-données) à propos des constructeurs d'un type de données Java.

Exemple de parcours de tous les constructeurs (publics ou non) exposés par une classe

Le programme ci-dessous liste l'ensemble des constructeurs présents dans la classe considérée.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
import java.lang.reflect.Constructor;


public class TestReflection {
        
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<?> metadata = TestReflection.class;
        
        // On récupère les constructeurs déclarés sur le type courant
        Constructor<?> [] constructors = metadata.getDeclaredConstructors();
        
        // On affiche des informations sur ces constructeurs
        for( Constructor<?> constructor : constructors ) {
            System.out.println( constructor.toString() );
        }
    
    }
    
}
Parcours de tous les constructeurs (publics ou non) exposés par une classe.

Et voici le résultat produit par ce programme :

public TestReflection()
cet exemple a le mérite de nous rappeler que si vous ne définissez aucun constructeur dans une classe alors un constructeur par défaut y est automatiquement produit. N'oubliez pas, un constructeur par défaut ne fait rien de particulier, hormis l'appel au constructeur à zéro paramètre de sa classe parente.

Manipulation des types sur lesquels est basée notre classe

Une classe est définie à partir d'un ou plusieurs types parents. Bien entendu, il n'y aura qu'un seul type parent en termes d'héritage, mais n'oubliez pas qu'une classe peut implémenter une ou plusieurs interfaces. Pour rappel, voici un exemple de déclaration de classe en Java.

 1 
 2 
 3 
 4 
 5 
public class Demo extends Parent implements Interface1, Interface2 {

    // TODO: implémentation de la classe à terminer.

}
Rappel sur la définition d'une classe en Java

L'API de réflexion Java permet de retrouver la classe parente que l'on étend, mais aussi l'ensemble des interfaces que la classe implémente.

Lister la hiérarchie d'héritage

L'exemple ci-dessus cherche à afficher toute la hiérarchie d'héritage pour une classe donnée. Il est donc aussi nécessaire de retrouver les données descriptives des types parents : c'est ce qui est fait dans la boucle while.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
import java.io.Serializable;

class Base { }

public class TestReflection extends Base {
            
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<?> metadata = TestReflection.class;

        StringBuilder builder = new StringBuilder( metadata.getName() );
        while ( true ) {
            // On remonte sur le type parent, s'il y en a un.
            metadata = metadata.getSuperclass();
            if ( metadata == null ) break;
            
            // On insert en tête du StringBuilder le nouveau niveau d'héritage
            builder.insert( 0, metadata.getName() + " -> " );
        }
        
        // On affiche la hiérarchie d'héritage
        System.out.println( builder.toString() );
    
    }
    
}

Et voici les résultats produits par cet exemple :

java.lang.Object -> Base -> TestReflection

Lister les interfaces implémentées par notre classe

Nous allons maintenant chercher à retrouver la liste des interfaces implémentées par une classe donnée. Nous ne considérerons que les interfaces directement implémentées par la classe considérée, mais en mixant le code ci-dessous avec celui de l'exemple précédent, vous devriez être en mesure de lister l'intégralité des interfaces implémentées sur tous les niveaux d'héritage.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
import java.io.Serializable;

interface NotListed {}

class Base implements NotListed { }

public class TestReflection extends Base implements Runnable, Serializable {
    
    @Override public void run() {}
        
    public static void main( String[] args ) throws Exception {
        
        // Récupération des méta-données à partir de la classe.
        Class<?> metadata = TestReflection.class;

        // On retrouve toutes les interfaces directement implémentées par le type considéré.
        Class<?> [] implementedInterfaces = metadata.getInterfaces();
        
        // On affiche ces interfaces.
        for( Class<?> interfaceMetadata : implementedInterfaces ) {
            System.out.println( interfaceMetadata.getName() );
        }
    
    }
    
}
On liste les interfaces implémentées par notre classe

Et voici les résultats produits par cet exemple.

java.lang.Runnable
java.io.Serializable

La réflexion dans le cadre de l'écriture de jeux de tests unitaires

Pour clore ce chapitre, je voudrais vous montrer une possibilité qui peut être très utiles dans certains cas : la possibilité d'accéder à des éléments privés de la classe à l'extérieur de celle-ci. Bien entendu, si une telle possibilité existe, elle serait en totale contradiction avec le principe d'encapsulation. Mais elle existe bel et bien. Du coup, notez bien que les exemples de code suivants sont à utiliser avec très grande sagesse.

Du coup, la bonne question à se poser est quand pouvons-nous, de manière acceptable, accéder à un membre privé d'une classe et donc violer le principe d'encapsulation. Un cas concret, c'est la mise en oeuvre d'une batterie de tests unitaires. Nous reviendrons plus sérieusement sur ce sujet dans des futurs chapitres, avec notamment la présentation de JUnit. Mais nous allons quand même imaginer maintenant que nous sommes en train de coder de telles procédures de tests.

Accès à un attribut privé

Dans la théorie des tests, il existe, entre autre, deux catégories de tests : les tests « boîtes noires » et les tests « boîtes blanches ». Dans un test « boîte noire », le SUT (System Under Test ou System Under Test) est considéré comme étant opaque. On y envoie des inputs (des données d'entrées) et on vérifie simplement que les outputs (les résultats) sont correctes. Au contraire, dans un test « boîte blanches » on vérifie durant l'exécution d'un test, l'état interne du SUT est bien cohérent : l'état interne d'un composant logiciel étant souvent privé, il est nécessaire de passer outre.

L'exemple de code suivant simule un scénario de test boîte blanche et l'on tente de vérifier l'état interne du SUT. Le problème c'est que ça ne va pas marcher.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
import java.lang.reflect.Field;

class Sut {
    
    private boolean stateToVerify = false;
    
    public boolean methodToTest( boolean input ) {
        stateToVerify = true;
        return ! input;
    }
    
}

public class TestReflection {
    
    public static void main( String[] args ) throws Exception {
        
        // On monte le scénario de tests
        Sut sut = new Sut();
        boolean result = sut.methodToTest( true );

        // On vérifie le résultat produit
        assert result == false;
        
        // On vérifie l'état interne du composant en test
        Class<Sut> metadata = Sut.class;
        Field probe = metadata.getDeclaredField( "stateToVerify" );
        boolean value = probe.getBoolean( sut );    // <- ne marche pas
        assert value == true;
    
    }
    
}
Tentative d'écriture d'un scénario de test de type boîte blanche
le mot anglais « probe » signifie en français « sonde ». Ce terme est fréquemment utilisé dans la mise en oeuvre de tests boites blanches.

Si vous lancez le programme ci-dessus, vous noterez les résultats suivants

$> java -ea TestReflection
Exception in thread "main" java.lang.IllegalAccessException: Class TestReflection can not access a member of class Sut with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Field.getBoolean(Field.java:425)
    at TestReflection.main(TestReflection.java:30)
l'option -ea (enable assertions) de la JVM permet d'activer la vérification des assertions. N'oubliez donc pas cette option si vous voulez que l'assert fasse son travail.

Si on analyse le message d'erreur produit, on constate que l'accès à un élément privé est quand même vérifié et du coup une erreur est produite. En fait, dans les méta-données, on retrouve aussi le niveau de visibilité. Par contre, dans la donnée, il n'y a pas d'information de cette nature. Si on indique au moteur de réflexion de ne pas tenir compte de la visibilité, on autorisera alors l'accès à l'attribut. Cela se fait en rajoutant un appel à la méthode probe.setAccessible( true ). Voici l'exemple de test désécurisé.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
import java.lang.reflect.Field;

interface NotListed {}

class Sut {
    
    private boolean stateToVerify = false;
    
    public boolean methodToTest( boolean input ) {
        stateToVerify = true;
        return ! input;
    }
    
}

public class TestReflection {
    
    public static void main( String[] args ) throws Exception {
        
        // On monte le scénario de tests
        Sut sut = new Sut();
        boolean result = sut.methodToTest( true );

        // On vérifie le résultat produit
        assert result == false;
        
        // On vérifie l'état interne du composant en test
        Class<Sut> metadata = Sut.class;
        Field probe = metadata.getDeclaredField( "stateToVerify" );
        probe.setAccessible( true );
        boolean value = probe.getBoolean( sut );
        assert value == true;
    
    }
    
}
Tentative d'écriture d'un scénario de test de type boîte blanche

Si vous lancez le test, cette fois-ci tout doit bien se passer et aucun affichage ne sera produit (c'est notre manière de dire que tout va bien).

Accès à une méthode privée

Un autre besoin, quand on écrit des scénarios de tests, est de vérifier qu'une méthode privée fonctionne correctement. Il serait dommage de changer la visibilité de la méthode juste pour l'écriture du test : dans ce cas, conservez la visibilité private et faite en sorte que votre test contourne cette visibilité restreinte. Cela passe aussi par l'emploi d'une méthode setAccessible sur l'objet méta-données associé à la méthode. En voici un exemple.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
import java.lang.reflect.Method;

interface NotListed {}

class Sut {
    
    private void doSomething( int a, int b ) {
        System.out.println( "On passe bien dans la méthode privée" );
        System.out.println( "avec a == " + a + " et b == " + b );
    }
    
}

public class TestReflection {
    
    public static void main( String[] args ) throws Exception {
        
        Sut sut = new Sut();

        Class<Sut> metadata = Sut.class;
        Method doSomethingMethod = metadata.getDeclaredMethod( "doSomething", int.class, int.class );
        doSomethingMethod.setAccessible( true );
        doSomethingMethod.invoke( sut, 10, 20 );
    
    }
    
}
On force l'appel à une méthode privée

Et voici les résultats produits par cet exemple.

On passe bien dans la méthode privée
avec a == 10 et b == 20

Pour conclure, gardez en mémoire qu'il est hors de question d'utiliser la réflexion pour utiliser des membres privés dans un code applicatif traditionnel. Sinon, faite directement du C, ce sera mieux pour vous ;-).



Définition de méthodes génériques Coder un moteur de sérialisation