80 votes

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

Il s'agit d'un suivi de cette question sur les constructeurs privés java .

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 puis-je construire un new Foo("hello") en utilisant la réflexion ?

RÉPONSE :

Sur la base de La 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);
    }   
}

3 votes

Cela ne fonctionne pas :( java.lang.NoSuchMethodException : my.package.path.Foo.<init>(java.lang.Object) at java.lang.Class.getConstructor0(Class.java:2892) at java.lang.Class. getDeclaredConstructor(Class.java:2058) at ProductCatalogAgentTest.testConnect(ProductCatalogAgentTest.java:461) at sun.reflect.NativeMethodAccessorImpl.invoke0(Méthode native)

57voto

Mohamed Mansour Points 18019

Assurez-vous d'utiliser getDeclaredConstructors lors de la récupération du constructeur et de mettre son accessibilité à true puisqu'il est privé.

Quelque chose comme ceci 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 voulez faire usage de getDeclaredConstructor, passez Object.class comme argument, ce 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);

0 votes

Je ne sais pas pourquoi, mais je reçois une exception disant que mon constructeur n'existe pas (il existe). Avez-vous une idée ? Plus d'informations

31voto

jtahlborn Points 32515

Il faudrait 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 l'attribut setAccessible ), et enfin l'invoquer avec l'argument souhaité.

6 votes

Cet article pourrait vous aider : dunwood.blogspot.com/2004/05/

11voto

Sanjay Madnani Points 11

Dans le cas où le constructeur privé ne prend pas d'argument, nous rencontrons un problème lors de la création d'une nouvelle instance, dans ce cas, après que setAccessible true, nous ne pouvons pas créer d'objet. Même construct.newInstance(null); ne créera pas d'objet pour le constructeur sans argument.

pouvons-nous créer un objet du 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 vous référer : Exemple 2 : "Eager Initialization" et "Singleton Violation by reflection" de mon blog : http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in-java/

3voto

simpatico Points 2730

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

Au lieu de @Test de JUnit, annotez la méthode dans laquelle vous souhaitez injecter Reflection 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 la réflexion, utilisez l'argument -Averbose=true comme dans l'exemple suivant cette réponse .

1voto

ArtB Points 3922

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X