Creazione di un'istanza usando il nome della classe e chiamando il costruttore


312

Esiste un modo per creare un'istanza di una particolare classe dato il nome della classe (dinamico) e passare i parametri al suo costruttore.

Qualcosa di simile a:

Object object = createInstance("mypackage.MyClass","MyAttributeValue");

Dov'è "MyAttributeValue"un argomento per il costruttore di MyClass.

Risposte:


497

Sì, qualcosa del tipo:

Class<?> clazz = Class.forName(className);
Constructor<?> ctor = clazz.getConstructor(String.class);
Object object = ctor.newInstance(new Object[] { ctorArgument });

Ovviamente funzionerà solo per un singolo parametro stringa, ma puoi modificarlo abbastanza facilmente.

Si noti che il nome della classe deve essere completo, cioè includendo lo spazio dei nomi. Per le classi nidificate, è necessario utilizzare un dollaro (poiché è quello che utilizza il compilatore). Per esempio:

package foo;

public class Outer
{
    public static class Nested {}
}

Per ottenere l' Classoggetto per quello, avresti bisogno Class.forName("foo.Outer$Nested").


5
newInstance()è un metodo varargs (proprio come GetConstructor()), non è necessario Objectcreare esplicitamente l' array.
Joachim Sauer,

18
@Joachim: so che è varargs, ma dato che può diventare complicato quando hai un Object[]argomento, preferisco creare l'array esplicitamente in questo caso.
Jon Skeet,

2
clazz.getConstructor (String.class); perché String.class qui?
Umair A.

2
@Neutralizer: Sì, ma stavo rispondendo a una domanda in cui non doveva essere dinamico.
Jon Skeet,

3
@JonSkeet Capisco da dove vieni, tuttavia non è così semplice - ho guardato i documenti ma ero confuso, ma anche se l'ho provato e ha funzionato - ok allora ha funzionato - ma se non ha funzionato allora Non sarei stato sicuro se il problema fosse dovuto a una mancanza di configurazione o a qualcosa da parte mia - spesso quando si fanno domande così semplici, le persone gettano cose utili che aiutano davvero. Ecco perché un semplice "sì che funzionerebbe - se lo fai in questo modo" o "no non c'è modo", aiuta davvero. Ma la mia comprensione ora è che non c'è modo
ycomp

97

È possibile utilizzare Class.forName()per ottenere un Classoggetto della classe desiderata.

Quindi utilizzare getConstructor()per trovare l' Constructoroggetto desiderato .

Infine, chiama newInstance()quell'oggetto per ottenere la tua nuova istanza.

Class<?> c = Class.forName("mypackage.MyClass");
Constructor<?> cons = c.getConstructor(String.class);
Object object = cons.newInstance("MyAttributeValue");

81

Puoi usare i riflessi

return Class.forName(className).getConstructor(String.class).newInstance(arg);

3
Se si utilizza il costruttore predefinito, rimuovere il valore del parametro String.class, ad esempio return Class.forName (className) .getConstructor (). NewInstance (arg);
Vijay Kumar,

21
@VijayKumar Penso che intendi Class.forName(className).getConstructor().newInstance();;)
Peter Lawrey il

14

Se la classe ha un solo costruttore vuoto (come Activity o Fragment ecc., Classi Android):

Class<?> myClass = Class.forName("com.example.MyClass");    
Constructor<?> constructor = myClass.getConstructors()[0];

2
Questo è ciò che mi ha aiutato. Constructor<?> ctor = clazz.getConstructor(String.class)non sembra funzionare per me.
Leo C Han,

8

quando si utilizza (cioè) getConstructor(String.lang)il costruttore deve essere dichiarato pubblico. Altrimenti NoSuchMethodExceptionviene lanciato a.

se vuoi accedere a un costruttore non pubblico devi invece usare (es getDeclaredConstructor(String.lang). ) .



4

Modo molto semplice per creare un oggetto in Java usando Class<?>con argomenti di costruzione che passano:

Caso 1: - Ecco un piccolo codice in questa Mainclasse:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        // Get class name as string.
        String myClassName = Base.class.getName();
        // Create class of type Base.
        Class<?> myClass = Class.forName(myClassName);
        // Create constructor call with argument types.
        Constructor<?> ctr = myClass.getConstructor(String.class);
        // Finally create object of type Base and pass data to constructor.
        String arg1 = "My User Data";
        Object object = ctr.newInstance(new Object[] { arg1 });
        // Type-cast and access the data from class Base.
        Base base = (Base)object;
        System.out.println(base.data);
    }

}

Ed ecco la Basestruttura della classe:

public class Base {

    public String data = null;

    public Base() 
    {
        data = "default";
        System.out.println("Base()");
    }

    public Base(String arg1) {
        data = arg1;
        System.out.println("Base("+arg1+")");
    }

}

Caso 2: - È possibile codificare in modo simile per costruttore con argomento multiplo e copia costruttore. Ad esempio, passando 3 argomenti come parametro al Basecostruttore sarà necessario creare il costruttore in classe e modificare il codice sopra come:

Constructor<?> ctr = myClass.getConstructor(String.class, String.class, String.class);
Object object = ctr.newInstance(new Object[] { "Arg1", "Arg2", "Arg3" }); 

E qui la classe Base dovrebbe in qualche modo apparire come:

public class Base {

    public Base(String a, String b, String c){
        // This constructor need to be created in this case.
    }   
}

Nota: - Non dimenticare di gestire le varie eccezioni che devono essere gestite nel codice.


Un altro modo è anche clone () l'oggetto java esistente. Questo crea una copia di un oggetto Java esistente. In questo caso, devi anche gestire il concetto Copia profonda o Copia superficiale.
Rahul Raina,

2

Se qualcuno è alla ricerca di un modo per creare un'istanza di una classe nonostante la classe segua il modello Singleton, ecco un modo per farlo.

// Get Class instance
Class<?> clazz = Class.forName("myPackage.MyClass");

// Get the private constructor.
Constructor<?> cons = clazz.getDeclaredConstructor();

// Since it is private, make it accessible.
cons.setAccessible(true);

// Create new object. 
Object obj = cons.newInstance();

Questo funziona solo per le classi che implementano il modello singleton usando un costruttore privato.


1

Puoi anche invocare metodi all'interno dell'oggetto creato.

È possibile creare un oggetto istantaneo invocando il primo fornitore e quindi invocare il primo metodo nell'oggetto creato.

    Class<?> c = Class.forName("mypackage.MyClass");
    Constructor<?> ctor = c.getConstructors()[0];
    Object object=ctor.newInstance(new Object[]{"ContstractorArgs"});
    c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs);

Come saprai che il primo costruttore prende Stringcome parametro? Diventa un po 'disordinato quando cambi l'ordine del costruttore
Farid

@Farid dalla documentazione di classe
Hatem Badawi

Comunque getConstructor(ClassName.class)è meglio, immagino. Anche se l'ordine dei costruttori cambia in classe, non è necessario trovare la posizione manualmente
Farid

@Farid - c.getDeclaredMethods () [0] .invoke (object, Object ... MethodArgs); specifica un costruttore speciale in alcuni casi che potrebbe essere necessario, ma hai ragione.
Hatem Badawi,

1

Un'altra risposta utile. Come posso usare getConstructor (params) .newInstance (args)?

return Class.forName(**complete classname**)
    .getConstructor(**here pass parameters passed in constructor**)
    .newInstance(**here pass arguments**);

Nel mio caso, il costruttore della mia classe prende Webdriver come parametro, quindi usato sotto il codice:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.