Duvida sobre a Classe Class

9 respostas
P

Bem estava lendo o artigo do Alexandre Gazola sobre Padroes e Projetos e Reflexao da revista mundo java e fikei com um duvida. O exemplo que ele utiliza sobre a classe Class é o seguinte :

public class Aluno {
    private String nome;
    private int matricula;

    public Aluno() {
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getMatricula() {
        return matricula;
    }   

}
public class TesteReflexao {
    
    public TesteReflexao() {
    }
    
    public static void main(String[] args){
        try{
            Class c = Class.forName("Aluno");
            System.out.println(c.getName());
            
            Aluno a = (Aluno) c.newInstance();
            
        }
        catch(InstantiationException e){
            e.printStackTrace();
        }
        catch(IllegalAccessException e){
            e.printStackTrace();
        }
        catch(ClassNotFoundException e){
            e.printStackTrace();
        }        
    }
}

Minha dúvida é a seguinte, tem como fazer algo parecido assim :

public class TesteReflexao {
    
    private static String minhaClasse = "Aluno";

    public TesteReflexao() {
    }
    
    public static void main(String[] args){
        try{
            Class c = Class.forName(minhaClasse);
            System.out.println(c.getName());
            
            minhaClasse a = (minhaClasse) c.newInstance();
            
        }
        catch(InstantiationException e){
            e.printStackTrace();
        }
        catch(IllegalAccessException e){
            e.printStackTrace();
        }
        catch(ClassNotFoundException e){
            e.printStackTrace();
        }        
    }
}
[/code]

9 Respostas

C

Não dá, porque minhaClasse é uma String e o método newInstance da classe Class retorna um objeto, ou seja, uma instância do objeto que você quer.

P

Carneiro, vc tem algum dica de como posso fazer algo parecido com essa minha dúvida

J

Não seria isso?

String minhaClasse = "Aluno";

Class clazz = Class.forName(minhaClasse);

Object obj = clazz.newInstance();
V

crie uma abstração para a classe aluno criando uma interface ou superclasse e quando for executar o Class.forName("Aluno").newInstance() faça o cast usando a superclasse ou interface.

interface InterAluno {...}
public class Aluno implements InterAluno {...}

InterAluno aluno = (InterAluno) Class.forName("Aluno").newInstance();

Deste modo vc tratará a instancia desta classe de uma maneira genérica/abstrata.

P

viecili, é isso msm que queria, mas sem kerer ser chato, gostaria de tirar mais uma duvida. Por exemplo se eu tivesse uma classe Professor junto com a classe Aluno, Pergunto: Tem como eu ter apenas uma Interface p/ essas duas Classes?

naum sei se é possivel ou se é o certo, mas tem como de ter algo assim:

interface Inter {...}
public class Aluno implements Inter {...}
public class Professor implements Inter{...}

Inter x = (Inter) Class.forName("Aluno" ou "Professor").newInstance();

E tipo depois tem como fazer isso:

Aluno aluno = new Aluno(); x = aluno; [/code]

C

Você poderia criar uma interface Pessoa e fazer essas classes implementar ela. Mas o correto seria criar as interfaces Docente e Discente, para professores e alunos.

L

Você pode fazer algo assim:

public class Teste {

	static <T> T createInstance(String clazzName) {
		try {
			Class<T> clazz = (Class<T>) Class.forName(clazzName);
			return clazz.newInstance();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;

	}

	public static void main(String[] args) {
		Teste x1 = createInstance("Teste");
		System.out.println(x1);
		String x2 = createInstance("Teste");
		System.out.println(x2);
	}

}

vai funcionar para qualquer atribuição que você quizer, e isso é ruim ehehe eu acho feio e errado, pois note que o retorno pode ser atribuido a um Teste ou String, mas a classe que vc passou no formato de String é um Teste, então não pode tentar fazer casting para String, vai dar ClassCastException, mas mesmo assim o compilador deixou compilar (probabilidade de dar erro em tempo de execução é grande).
Porém, o compilador mostra que isso pode ocorrer dando um warning nessa linha

Class<T> clazz = (Class<T>) Class.forName(clazzName);

Já que você não garante o retorno de forName.

Para resolver isso, vc pode passar junto como parâmetro, o tipo que você vai atribuir na igualdade:

public class Teste {

	static <T> T createInstance(String clazzName, Class<T> castClazz) {
		try {
			Class<?> clazz = Class.forName(clazzName);

			if (castClazz.isAssignableFrom(clazz)) {
				Object o = clazz.newInstance();
				return castClazz.cast(o);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;

	}

	public static void main(String[] args) {
		Teste x1 = createInstance("Teste", Teste.class);
		System.out.println(x1);
		// String x2 = createInstance("Teste", Teste.class); //erro de
		// compilação
		String x2 = createInstance("Teste", String.class);
		System.out.println(x2);
	}

}

Dessa forma vc checa se a conversão é possivel:

if (castClazz.isAssignableFrom(clazz))

Cria a instancia do objeto e faz o casting:

Object o = clazz.newInstance();
				return castClazz.cast(o);

ou seja, verifica se o tipo que vai ser atribuido é compativel com o tipo da classe que veio do forName, caso contrário ele retorna null (ou lança uma exceção seila, depende do tratamento que vc quer fazer)

E note que se vc tentar fazer:

String x2 = createInstance("Teste", Teste.class);

O compilador vai reclamar, porque vc tah dizendo que vai fazer um casting para Teste quando na real esta atribuindo a uma String.

É uma forma de fazer isso que você quer… espero ter ajudado.

V

Perk,

isso q vc falou eh possível sim, entretanto como seu objeto 'x' foi declarado como um objeto do tipo 'Inter' vc somente poderá executar métodos definidos na interface 'Inter', isto é, se vc tiver métodos específicos da classe Aluno vc não poderá executá-los, a não ser q vc faça o cast apropriado.

Inter x = (Inter) Class.forName("Aluno").newInstance();

...

x.metodoComum();

...

if (x instanceof Aluno) {
  ((Aluno) x).metodoEspAluno();
} else if (x instanceof Professor) {
  ((Professor) x).metodoEspProfessor();
}

Enfim, embora tudo isso seja possível, não parece ser uma solução muito Orientada a Objeto, talvez se vc disser o que vc quer fazer fica mais facil dar uma dica melhor.

Outra coisa, reflection adiciona um overhead enorme nas aplicações, então não abuse.

PS.: luBS, mataste um pardal com um canhão agora! Qm sabe um try...catch não resolvesse o problema, afinal isso seria RuntimeException, i.e., erro do programador ou do ambiente.

L

Como eu disse, é uma forma de fazer o que ele quer de forma checada hehe não sei para que ele quer, então ta ai mais uma opção eheh

Criado 24 de maio de 2007
Ultima resposta 24 de mai. de 2007
Respostas 9
Participantes 5