Czy istnieje sposób na utworzenie wystąpienia klasy według nazwy w Javie?

102

Szukałem pytania: Utwórz instancję klasy na podstawie jej nazwy ciągu, która opisuje, jak utworzyć instancję klasy, mając jej nazwę. Czy można to zrobić w Javie? Będę mieć nazwę pakietu i nazwę klasy i muszę mieć możliwość utworzenia obiektu o tej konkretnej nazwie.

ict1991
źródło
Mamy instancję do klasy , a wynik jest obiekt (czyli instancja ).
Andreas Dolk
1
Odpowiedź brzmi: tak, ale myślę, że powinieneś zapytać, czy to dobry pomysł. Z wielką mocą (refleksją) wiąże się wielka odpowiedzialność i powinieneś jej używać tylko wtedy, gdy rozumiesz i rozważasz konsekwencje.
c1moore

Odpowiedzi:

239

Dwie drogi:

Metoda 1 - tylko dla klas posiadających konstruktor bezargumentowy

Jeśli Twoja klasa ma konstruktor bez argumentów, możesz uzyskać Classobiekt za Class.forName()pomocą newInstance()metody i użyć tej metody do utworzenia instancji (chociaż uważaj, że ta metoda jest często uważana za złą, ponieważ może pokonać sprawdzone wyjątki Javy).

Na przykład:

Class<?> clazz = Class.forName("java.util.Date");
Object date = clazz.newInstance();

Metoda 2

Alternatywnym bezpieczniejszym podejściem, które działa również, jeśli klasa nie ma żadnych konstruktorów bez argumentów, jest Constructorwysłanie zapytania do obiektu klasy w celu pobrania obiektu i wywołania newInstance()metody na tym obiekcie:

Class<?> clazz = Class.forName("com.foo.MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
Object instance = constructor.newInstance("stringparam", 42);

Obie metody znane są jako odbicie . Zazwyczaj będziesz musiał wychwycić różne wyjątki, które mogą wystąpić, w tym takie jak:

  • JVM nie może znaleźć lub załadować twojej klasy
  • klasa, którą próbujesz utworzyć, nie ma odpowiedniego rodzaju konstruktorów
  • sam konstruktor zgłosił wyjątek
  • konstruktor, który próbujesz wywołać, nie jest publiczny
  • Menedżer bezpieczeństwa został zainstalowany i zapobiega występowaniu refleksji
Simon Nickerson
źródło
cześć, po utworzeniu obiektu z newInstance(), czy moglibyśmy rzucić go z powrotem na nasz własny obiekt?
GMsoF
@Simon czy możesz rozwinąć / podać wskazówkę dotyczącą menedżera bezpieczeństwa?
Ram
Nie rozumiem tego. Chcę uzyskać dostęp do klasy w nieznanym pliku w innym katalogu, mam tylko nazwę ścieżki / pliku jako ciąg. Ciąg „dir / unkonwn.java”. Wywołanie Class.forName („dir / unknown”) powoduje wyświetlenie błędów.
john ktejik
Jak możemy rzucić instancesię com.foo.MyClass? biorąc pod uwagę, że com.foo.MyClass to tylko ciąg znaków
Sanket9394
14
MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();
scibuff
źródło
15
Warto wspomnieć, że to nie działa, jeśli klasa nie ma konstruktora bez parametrów (i ma inne konstruktory) lub jeśli konstruktor bez parametrów jest niedostępny.
Dawood ibn Kareem
3

use Class.forName ("String nazwa klasy"). newInstance ();

Class.forName("A").newInstance();

Spowoduje to zainicjowanie klasy o nazwie A.

Chandra Sekhar
źródło
U mnie nie działa, nawet z dołączoną nazwą pakietu. :(
trusktr
3

Aby ułatwić uzyskanie w pełni kwalifikowanej nazwy klasy w celu utworzenia instancji za pomocą Class.forName(...), można skorzystać z Class.getName()metody. Coś jak:

class ObjectMaker {
    // Constructor, fields, initialization, etc...
    public Object makeObject(Class<?> clazz) {
        Object o = null;

        try {
            o = Class.forName(clazz.getName()).newInstance();
        } catch (ClassNotFoundException e) {
            // There may be other exceptions to throw here, 
            // but I'm writing this from memory.
            e.printStackTrace();
        }

        return o;
    }
}

Następnie możesz rzucić obiekt, do którego wracasz, z powrotem do dowolnej klasy, do której przejdziesz makeObject(...):

Data d = (Data) objectMaker.makeObject(Data.class);
Roberto
źródło
1
Nie możesz po prostu clazz.newInstance()zamiast getNamewtedy fromName?
user276648
1

Użyj odbicia Java

Tworzenie nowych obiektów Nie ma odpowiednika wywołania metody dla konstruktorów, ponieważ wywołanie konstruktora jest równoznaczne z utworzeniem nowego obiektu (aby być bardziej precyzyjnym, utworzenie nowego obiektu wymaga zarówno alokacji pamięci, jak i konstrukcji obiektu). Zatem najbliższy odpowiednik poprzedniego przykładu to:

import java.lang.reflect.*;

   public class constructor2 {
      public constructor2()
      {
      }

      public constructor2(int a, int b)
      {
         System.out.println(
           "a = " + a + " b = " + b);
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct 
              = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

która znajduje konstruktora, który obsługuje określone typy parametrów i wywołuje go, aby utworzyć nowe wystąpienie obiektu. Wartość tego podejścia polega na tym, że jest czysto dynamiczne, z wyszukiwaniem konstruktora i wywoływaniem w czasie wykonywania, a nie w czasie kompilacji.

kornero
źródło
1

Class.forName („ClassName”) rozwiąże Twój cel.

Class class1 = Class.forName(ClassName);
Object object1 = class1.newInstance();
Balaswamy Vaddeman
źródło
0
String str = (String)Class.forName("java.lang.String").newInstance();
Chen Harel
źródło
0

coś takiego powinno działać ...

String name = "Test2";//Name of the class
        Class myClass = Class.forName(name);
        Object o = myClass.newInstance();
Shashank Kadne
źródło
0

Używanie newInstance()bezpośrednie jest przestarzałe od wersji Java 8. Należy używać Class.getDeclaredConstructor(...).newInstance(...)z odpowiednimi wyjątkami.

Mel
źródło