web-dev-qa-db-fra.com

Java: accès au constructeur privé avec les paramètres de type

Ceci est un suivi de cette question sur Java constructeurs privés .

Supposons que j'ai la classe suivante:

class Foo<T>
{
    private T arg;
    private Foo(T t) {
        // private!
        this.arg = t;
    }   

    @Override
    public String toString() {
        return "My argument is: " + arg;
    }   
}

Comment pourrais-je construire une new Foo("hello") en utilisant la réflexion?

[~ # ~] réponse [~ # ~]

Basé sur réponse de jtahlborn , les travaux suivants:

public class Example {
    public static void main(final String[] args) throws Exception {
        Constructor<Foo> constructor;
        constructor = Foo.class.getDeclaredConstructor(Object.class);
        constructor.setAccessible(true);
        Foo<String> foo = constructor.newInstance("arg1");
        System.out.println(foo);
    }   
}
65
dsg

vous devez obtenir la classe, trouver le constructeur qui prend un seul argument avec la borne inférieure de T (dans ce cas, Object), forcer le constructeur à être accessible (en utilisant la méthode setAccessible), et enfin invoquer avec l'argument souhaité.

28
jtahlborn

Assurez-vous d'utiliser getDeclaredConstructors lors de l'obtention du constructeur et définissez son accessibilité sur true depuis son caractère privé.

Quelque chose comme ça devrait fonctionner.

Constructor<Foo> constructor= (Constructor<Foo>) Foo.class.getDeclaredConstructors()[0];
constructor.setAccessible(true); 
Foo obj = constructor.newInstance("foo"); 
System.out.println(obj);

Mise à jour

Si vous souhaitez utiliser getDeclaredConstructor, passez Object.class comme argument qui se traduit par un T. générique.

Class fooClazz = Class.forName("path.to.package.Foo");
Constructor<Foo> constructor = fooClazz.getDeclaredConstructor(Object.class);
constructor.setAccessible(true); 
Foo obj = constructor.newInstance("foo"); 
System.out.println(obj);
45
Mohamed Mansour

Eh bien, si le constructeur privé ne prend aucun argument, nous récupérons le problème lors de la création d'une nouvelle instance, dans ce cas, après setAccessible true, nous ne pouvons pas créer d'objet. Même construct.newInstance(null); ne créera pas d'objet pour aucun constructeur d'argument.

pouvons-nous créer un objet de code ci-dessous en utilisant la réflexion:

public class Singleton {

    private static Singleton instance = new Singleton();

    /* private constructor */
    private Singleton() {}

    public static Singleton getDefaultInstance() {
        return instance;
    }
}

Oui, nous pouvons créer l'objet de la classe ci-dessus.

// reflection concept to get constructor of a Singleton class.  
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();

// change the accessibility of constructor for outside a class object creation.  
constructor.setAccessible(true);

// creates object of a class as constructor is accessible now.  
Singleton secondOb = constructor.newInstance();

// close the accessibility of a constructor.
constructor.setAccessible(false);

Vous pouvez consulter: Exemple 2: "Initialisation désireuse" et "Violation de Singleton par réflexion" de mon blog: http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in- Java /

9
Sanjay Madnani

Comme @ArtB l'a dit, vous pouvez utiliser dp4j.com , si vous connaissez le constructeur que vous souhaitez utiliser au moment de la compilation . Sur la page d'accueil du projet, il y a un exemple de cela, l'accès à un constructeur Singleton.

Au lieu de @Test de JUnit, annotez la méthode pour injecter la réflexion avec @Reflect:

public class Example {
    @com.dp4j.Reflect
    public static void main(final String[] args){
        Foo<String> foo = new Foo("hello");
        System.out.println(foo);
    }   
}

Pour voir le code généré par réflexion, utilisez l'argument -Averbose = true comme dans cette réponse .

3
simpatico

Si la classe de test Junit (dans le dossier de test) a le même nom de package que la classe réelle, alors à partir du cas de test Junit, nous pouvons appeler toutes les méthodes privées à tester, sans bibliothèque supplémentaire comme dp4j.

2
Coder

Il existe une bibliothèque pour JUnit ( dp4j ) qui insère automatiquement le code pour accéder aux méthodes privées. Cela peut être utile.

1
Tobogganski

Au début, je recevais NoSuchMethodException en utilisant la réflexion.

Utilisez ceci:

Constructor<TestClass> constructor= (Constructor<TestClass>) TestClass.class.getDeclaredConstructors()[0];
0
baidehi ghosh