Existe uma maneira de instanciar uma classe por nome em Java?

102

Eu estava procurando a pergunta: instanciar uma classe a partir de seu nome de string, que descreve como instanciar uma classe ao ter seu nome. Existe uma maneira de fazer isso em Java? Terei o nome do pacote e o nome da classe e preciso ser capaz de criar um objeto com esse nome específico.

ict1991
fonte
Nós instanciar uma classe eo resultado é um objeto (ou: exemplo ).
Andreas Dolk
1
A resposta é sim, mas acho que você deveria perguntar se é uma boa ideia. Com grande poder (reflexão) vem grande responsabilidade e você só deve usá-la se entender e considerar as consequências.
c1moore

Respostas:

239

Dois caminhos:

Método 1 - apenas para classes com um construtor sem arg

Se sua classe tiver um construtor sem arg, você pode obter um Classobjeto usando Class.forName()e usar o newInstance()método para criar uma instância (embora esteja ciente de que esse método é freqüentemente considerado mal porque pode derrotar as exceções verificadas do Java).

Por exemplo:

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

Método 2

Uma abordagem alternativa mais segura que também funciona se a classe não tiver nenhum construtor sem arg é consultar seu objeto de classe para obter seu Constructorobjeto e chamar um newInstance()método neste objeto:

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

Ambos os métodos são conhecidos como reflexão . Normalmente, você terá que capturar as várias exceções que podem ocorrer, incluindo coisas como:

  • a JVM não consegue encontrar ou carregar sua classe
  • a classe que você está tentando instanciar não tem o tipo certo de construtores
  • o próprio construtor lançou uma exceção
  • o construtor que você está tentando invocar não é público
  • um gerenciador de segurança foi instalado e está evitando que ocorra reflexão
Simon Nickerson
fonte
oi, uma vez que tenhamos criado o objeto newInstance(), poderíamos lançá-lo de volta para o nosso próprio objeto?
GMsoF
@Simon você pode elaborar / dar dicas sobre o gerenciador de segurança?
Ram
Eu não entendo isso. Quero acessar uma classe em um arquivo desconhecido em algum outro diretório, só tenho o nome do caminho / arquivo como uma string. String "dir / unkonwn.java". Chamar Class.forName ("dir / desconhecido") me dá erros.
john ktejik
Como podemos lançar instancepara com.foo.MyClass? dado que com.foo.MyClass é apenas uma string
Sanket9394
14
MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();
Scibuff
fonte
15
Vale a pena mencionar que isso não funciona se a classe não tiver nenhum construtor sem parâmetros (e tiver outros construtores), ou se o construtor sem parâmetros estiver inacessível.
Dawood ibn Kareem
3

use Class.forName ("String nome da classe"). newInstance ();

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

Isso fará com que a classe chamada A seja inicializada.

Chandra Sekhar
fonte
NÃO funciona para mim, mesmo com o nome do pacote prefixado. :(
trusktr
3

Para tornar mais fácil obter o nome totalmente qualificado de uma classe para criar uma instância usando Class.forName(...), pode-se usar o Class.getName()método. Algo como:

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;
    }
}

Em seguida, você pode lançar o objeto que você recebe de volta para qualquer classe que você passar makeObject(...):

Data d = (Data) objectMaker.makeObject(Data.class);
Roberto
fonte
1
Você não pode simplesmente em clazz.newInstance()vez do getNameentão fromName?
user276648
1

Use reflexão java

Criando Novos Objetos Não há equivalente à invocação de método para construtores, porque invocar um construtor é equivalente a criar um novo objeto (para ser mais preciso, criar um novo objeto envolve tanto alocação de memória quanto construção de objeto). Portanto, o equivalente mais próximo do exemplo anterior é dizer:

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);
         }
      }
   }

que encontra um construtor que lida com os tipos de parâmetro especificados e o invoca, para criar uma nova instância do objeto. O valor dessa abordagem é que ela é puramente dinâmica, com pesquisa e invocação do construtor no tempo de execução, em vez de no tempo de compilação.

Kornero
fonte
1

Class.forName ("ClassName") resolverá seu propósito.

Class class1 = Class.forName(ClassName);
Object object1 = class1.newInstance();
Balaswamy Vaddeman
fonte
0
String str = (String)Class.forName("java.lang.String").newInstance();
Chen Harel
fonte
0

algo assim deve funcionar ...

String name = "Test2";//Name of the class
        Class myClass = Class.forName(name);
        Object o = myClass.newInstance();
Shashank Kadne
fonte
0

O uso newInstance()direto está obsoleto no Java 8. Você precisa usar Class.getDeclaredConstructor(...).newInstance(...)com as exceções correspondentes.

Mel
fonte