Criar um objeto em tempode execução sem conhecer o nome

10 respostas
F

Gostaria de saber se em java eu posso criar um objeto em tempo de execução sem conhecer previamente seu nome, o usuário daria um nome e eu criaria este objeto.

Exemplo:

O usuário entra com um nome e guarda isso dentro de um array chamada NovoObj:

Usuario informa -> Nome do objeto: TESTE

Ai eu criaria algo do tipo:

Calandar (NovoObj[1]) = new GregorianCalendar();

Mas na verdade não quero criar o objeto Calendar com o nome NovoObj, o que quero é que crie com o nome que o usuário acabou de informar: TESTE e eu possa me referenciar a ele sempre que desejar pelo array NovoOBJ[1]

Qual é o procedimento?

10 Respostas

T

Use um Map &lt String, Object &gt , não um array.

Exemplo:

Map <String, Object> mapa = new TreeMap <String, Object> ();
// criar um objeto e atribuir um nome
mapa.put ("TESTE", new GregorianCalendar());
...
// recuperar um objeto pelo nome
Calendar cal = (Calendar) mapa.get ("TESTE");
// listar os objetos 
System.out.println (mapa);
V

Dá também para criar o objeto, se o objeto estiver no seu class path, e você conhecer o seu construtor.
É uma boa idéia também esse objeto implementar alguma interface.

Por exemplo, no caso de ter um construtor sem parâmetros:

String className = JOptionPane.showInputDialog(null, "Entre com o nome da classe:"); Class&lt?&gt clazz = Class.forName(className); SuaInterface obj = (SuaInterface)clazz.newInstance();

No caso de ter um construtor não default, dê uma olhada no método getConstructors() e na classe Constructor do pacote java.lang.reflect.

F

Thingo, não entendi sua referencia.

O único local onde eu poderia criar uma referencia onde não conheço o objeto é o “TESTE”, onde poderia passar uma string digitada pelo usuário. O resto, é tudo código que não da pra mudar em tempo de execução. E TESTE não se tornou um objeto como eu imaginava que aconteceria.

O exemplo que me deu vocês faz referencia a cal, mas cal é a minha chamada com um objeto fixo (calendar), isso é imutável.

Quando ao ViniGodoy, obrigado pela resposta mas não consegui criar um exemplo para poder entender exatamente o que esta falando.

Venho de uma linguagem que quando desejo criar um objeto eu coloco:

Public minhaclasse;
minhaclasse="TESTE"
objCustom(1) = createobject(minhaclasse);

Que pensei que em java seria algo do tipo:

String minhaclasse = "TESTE"; (minhaclasse) objCustom(1) = new (minhaclasse); // Não funcionou :(
Assim, eu não crio o objeto baseado em uma classe “minhaclasse” e sim, um objeto baseado na classe “TESTE”

Assim eu posso passar um variável como uma string para “minha classe” e quando necessito me referenciar a ela, posso fazer assim:

objCustom(1).fazeralgo();

Assim, objCustom é a referencia conhecida da classe “TESTE” que eu não conheço só sei que esta apontada na variável “minhaclasse”, que eventualmente pode ser qualquer classe, mas uma vez instanciada tenho acesso sem necessáriamente conhece-lá a principio, só fazer um reflection depois para saber se posso ou não executar um processo ou outro.

Deu para entender?

V

No exemplo que eu dei:

Class&lt?&gt clazz = Class.forName("TESTE"); Teste obj = (Teste)clazz.newInstance();

T

Hum, é que sou um tanto bitolado e não tinha entendido o que você queria. Quando você perguntou sobre um OBJETO achei que era um OBJETO, não uma CLASSE. Você queria instanciar um objeto de uma CLASSE pelo nome da CLASSE (como é o caso do VB e do VBScript, onde na verdade você instancia CLASSES).

F

Desculpe, mas a ignorancia em java me faz não entender absolutamente nada deste código:

Class<?> clazz = Class.forName("TESTE"); Teste obj = (Teste)clazz.newInstance();

Coloco esse no netbeans e me dá ero ao executá-lo, informe que Teste não fio definido.

Quanto ao Thingol, bitolado sou eu em java :slight_smile: pois não conheço os termos que normalmente vocês usam e acho que me expressei errado, pois para mim, qualquer classe depois de instanciada, essa instancia é um objeto. Por isso falo de objeto e classe quase da mesma forma, pois para usar a classe tenho que sempre instancia-la em um objeto. Claro que na minha humilde opnião de leigo e dentro da linguagem que domino.

No mais, não tem como me dar um exemplo pratico para isso?

public class void Teste1() {
             public static void hw() {
                             System.out.println("Hello Word"); 
                    }
             } 

String MinhaClasse = "Teste1";

(MinhaClasse) MeuObj(1) = new  (MinhaClasse);

MeuObj(1).hw();

Não sei como fazer isso funcionar em Java. pois não sei como referenciar “Minhaclasse” neste caso. Ai eu não necessito saber o nome da classe, use a referencia da string “MinhaClasse” e sempre uso a partir dai o objeto MeuObj.

Muito obrigado.

T

Tá bom, vou mostrar um programa completo como exemplo.

Me dá um tempo.

T

Compile e rode este programa (a classe principal é "TesteInstanciarPorNome").

import java.lang.reflect.*;

// Exemplo 1. Você tem várias classes que têm um
// método comum chamado "hw" (mais precisamente,
// public int hw (String msg)). Como você não
// pode mudar o código das classes, você tem de:
// a) Instanciar um objeto dessa classe (com sorte,
// essa classe tem um construtor sem parâmetros)
// b) Verificar se a classe desse objeto contém um
// método chamado "hw" que tem apenas um parâmetro String
// c) Chamar o método
// d) Cruzar os dedos para ver se não houve alguma Exception.

/** Uma classe que tem um construtor sem parâmetros, e que tem um método hw */
class ClasseA {
    public int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        return 0;
    }
    public ClasseA () {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", sem parâmetros");    
    }
    public ClasseA (int x) {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", com o parâmetro x = " + x);    
    }
}

/** Uma classe que não tem um construtor sem parâmetros, mas que tem um método hw */
class ClasseB {
    public int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        return 1;
    }
    public ClasseB (int x) {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", com o parâmetro x = " + x);    
    }
}

/** Uma classe que tem um construtor sem parâmetros (é o construtor default),
 * mas que não tem um método hw que tem apenas 1 parâmetro String */
class ClasseC {
    public int hw (int msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        return 2;
    }
}
/**
 * Uma classe que não tem um método hw 
 */
class ClasseD {
}

/**
 * Esta classe tem um método hw, mas ele é privado.
 */
class ClasseE {
    protected int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        return 0;
    }
}

/**
 * Esta classe é OK, como a classe ClasseA, mas o método hw provoca
 * uma exceção.
 */
class ClasseF {
    public int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        throw new RuntimeException ("Exceção provocada de propósito");
    }
    public ClasseF () {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", sem parâmetros");    
    }
    public ClasseF (int x) {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", com o parâmetro x = " + x);    
    }
}

class TesteInstanciarPorNome {
     public static void teste (String nomeClasse) {
         System.out.println ("Início do teste para " + nomeClasse);
         try {
         // Tentamos carregar a classe
         Class&lt?&gt klass = Class.forName (nomeClasse);
         // A seguir, tentamos instanciar um objeto desta classe
         // Note que, como não sabemos o tipo ou alguma interface dessa
         // classe, só podemos afirmar que o objeto é um java.lang.Object
         Object obj = klass.newInstance();
         // Agora vamos tentar ver se há um método "hw" com 1 parâmetro String
         Method meth = klass.getMethod ("hw", new Class[]{String.class});
         // Uma vez que o método foi encontrado, vamos chamá-lo com os parâmetros adequados
         meth.invoke (obj, new Object[]{"Mensagem do planeta Terra"});
         // Não é preciso fazer isto que você faria no VB (Set Obj = Nothing)
         // mas vamos escrever aqui o equivalente:
         obj = null;
         } catch (ClassNotFoundException ex) {
             System.out.println ("A classe " + nomeClasse + " não foi encontrada.");
         } catch (InstantiationException ex) {
             System.out.println ("A classe " + nomeClasse + " não tem um construtor público sem parâmetros. ");
         } catch (NoSuchMethodException ex) {
             System.out.println ("O método hw(String) não foi encontrado em " + nomeClasse + ".");
         } catch (IllegalAccessException ex) {
             System.out.println ("O método hw(String) é privado na classe " + nomeClasse + ".");
         } catch (InvocationTargetException ex) {
             System.out.println ("Ocorreu uma exceção no método hw da classe " + nomeClasse + ". A exceção ocorrida foi");
             ex.getTargetException().printStackTrace();
         } finally {
             System.out.println ("Fim do teste para " + nomeClasse);
             System.out.println();
         }
     }


     public static void main(String[] args) {
         teste ("ClasseA");
         teste ("ClasseB");
         teste ("ClasseC");
         teste ("ClasseD");
         teste ("ClasseE");
         teste ("ClasseF");
         teste ("ClasseG");
     }
}
T

O exemplo abaixo é como chamar uma classe por nome se você puder
fazer com que ela implemente uma determinada interface.

import java.lang.reflect.*;

// Exemplo 2. Você tem várias classes que têm um
// método comum chamado "hw" (mais precisamente,
// public int hw (String msg)). Se puder mudar o
// código das classes, então é um pouco mais fácil trabalhar.
// a) Faça com que as classes implementem uma mesma interface,
// que inclui esse método
// a) Instanciar um objeto dessa classe (com sorte,
// essa classe tem um construtor sem parâmetros)
// b) Verificar se o objeto implementa a tal interface.
// c) Chamar o método
// d) Cruzar os dedos para ver se não houve alguma Exception.

/** A interface a ser implementada */
interface Ihw {
     public int hw (String msg);
}

/** Uma classe que tem um construtor sem parâmetros, e que tem um método hw */
class ClasseA implements Ihw {
    public int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        return 0;
    }
    public ClasseA () {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", sem parâmetros");    
    }
    public ClasseA (int x) {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", com o parâmetro x = " + x);    
    }
}

/** Uma classe que não tem um construtor sem parâmetros, mas que tem um método hw */
class ClasseB implements Ihw {
    public int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        return 1;
    }
    public ClasseB (int x) {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", com o parâmetro x = " + x);    
    }
}

/** 
  A classe a seguir nem compila, pois não implementa Ihw corretamente.
  Portanto comentei a classe, para não dar problemas de compilação.  
 */
//class ClasseC implements Ihw {
//    public int hw (int msg) {
//        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
//        return 2;
//    }
//}
/**
 * Uma classe que não tem um método hw 
 */
class ClasseD {
}


/**
 * Esta classe é OK, como a classe ClasseA, mas o método hw provoca
 * uma exceção.
 */
class ClasseE implements Ihw {
    public int hw (String msg) {
        System.out.println ("Chamado o método hw da classe " + this.getClass().getName() + " com o parâmetro msg = " + msg);
        throw new RuntimeException ("Exceção provocada de propósito");
    }
    public ClasseE () {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", sem parâmetros");    
    }
    public ClasseE (int x) {
        System.out.println ("Chamado o construtor da classe" + this.getClass() + ", com o parâmetro x = " + x);    
    }
}

class TesteInstanciarPorNome2 {
     public static void teste (String nomeClasse) {
         System.out.println ("Início do teste para " + nomeClasse);
         try {
             // Tentamos carregar a classe
             // Note que usamos "asSubClass" para forçar um pouco...
             Class&lt? extends Ihw&gt klass = Class.forName (nomeClasse).asSubclass(Ihw.class);
             // A seguir, tentamos instanciar um objeto desta classe
             // Note que neste caso já sabemos que o objeto implementa Ihw.
             Ihw obj = klass.newInstance();
             // Agora é só chamar o método hw... Muito mais fácil.
             int ret = obj.hw ("Mensagem do planeta Terra");
             // Não é preciso fazer isto que você faria no VB (Set Obj = Nothing)
             // mas vamos escrever aqui o equivalente:
             obj = null;
         } catch (ClassCastException ex) {
             System.out.println ("A classe " + nomeClasse + " não implementa Ihw.");
         } catch (ClassNotFoundException ex) {
             System.out.println ("A classe " + nomeClasse + " não foi encontrada.");
         } catch (InstantiationException ex) {
             System.out.println ("A classe " + nomeClasse + " não tem um construtor público sem parâmetros. ");
         } catch (IllegalAccessException ex) {
             System.out.println ("O método hw(String) é privado na classe " + nomeClasse + ".");
         } catch (RuntimeException ex) {
             ex.printStackTrace(); 
         } finally {
             System.out.println ("Fim do teste para " + nomeClasse);
             System.out.println();
         }
     }


     public static void main(String[] args) {
         teste ("ClasseA");
         teste ("ClasseB");
//         teste ("ClasseC");
         teste ("ClasseD");
         teste ("ClasseE");
         teste ("ClasseF");
     }
}
F

Excelente era isso que estava procurando!

Ótimo exemplo, claro e simples.

Já implementado. Obrigado mesmo.

Criado 8 de maio de 2007
Ultima resposta 10 de mai. de 2007
Respostas 10
Participantes 3