[RESOLVIDO] Como saber a classe de um objeto null? [onde n podemos chamar getClass()]

Isto está contido no .class, independente das flags de compilação. Em debug, somente numeros de linha constam a mais.

Reflection é parte integrante do sistema.

[quote=Aldrin Leal]
Você esqueceu o detalhe sutil da coisa: O que define o método é, na ordem, é:

  • Classe
  • Nome
  • Tipos do Argumento (<- E ISTO ENVOLVE O Class<?>[])

A idéia do InvokeAdapter é apenas usar o mínimo possível da Reflection. E quando o fizê-lo, não ser por Object.getClass(), e sim pela definição do InvokeAdapter.

Enfim, boa sorte. Você irá precisar dela :)[/quote]

Acho que vc não acompanhou a thread direito e nem entendeu a minha necessidade.

Claro que isso que vc informou é o que é necessário pra invocar um método e eu não quero de maneira alguma invocar o método sem no final das contas informar as classes dos argumentos. O que eu quero saber é justamente se é possível não informar diretamente o “Tipos do Argumento (<- E ISTO ENVOLVE O Class<?>[])” que vc citou e aproveitando que eu preciso passar os argumentos ao método, inferir seus tipos usando algum método estático de alguma classe java (se existir).

Acho que vc confundiu o que eu quis dizer em relação à comparação que eu fiz entre o uso dos métodos. Em momento algum tive a intenção de dizer que o método que eu escrevi é melhor que o seu. Mas convenhamos, que diferente do que o tal H. L. Mencken disse, aquela forma de chamar um método que eu escrevi acaba sendo mais simples e não está errada.

Em termos de código, o que eu quero saber é se é possível fazer algo como isso:

public Object invocaMetodo(Object objeto, String nomeMetodo, Object[] argumentoObjetos) throws Exception {
    Class<?>[] argumentoClasses = METODO_MAGICO_DE_API_MAGICA(argumentoObjetos);
    Method metodo = objeto.getClass().getMethod(nomeMetodo, argumentosClasses);
    return metodo.invoke(action, argumentosObjetos);
 }

Ou seja, eu estaria abstraindo de quem vai chamar o método invocaMetodo a necessidade de informar as classes dos argumentos, mas internamente, mais uma vez se existisse o METODO_MAGICO_DE_API_MAGICA (que é a única resposta de que estou precisando nessa thread), na chamada à API Reflection eu estaria informando sim as classes dos argumentos.

Depois que vi o código que postei acima, percebi que acho que não seja possível, mas não por algumas justificativas que li por aí, mas por causa do seguinte:

o que eu estava querendo era um METODO_MAGICO_DE_API_MAGICA(objeto); que fizesse o seguinte:

  1. se o objeto tiver instancia, entao retorna o tipo da instancia.
  2. se o objeto for null, entao retorna o tipo da variável.

Porém, se vc for imaginar como seria o corpo desse método, teríamos o seguinte:

Para atender a todos os casos, ele teria que ser ± assim (atenção na assinatura):

public static Class<?> METODO_MAGICO_DE_API_MAGICA(Object object){
   if(object != null){
      return object.getClass();
   }else{
      return //faz a mágina com object pra retornar o tipo da variável object.
   }
}

Porém, dentro desse método, o tipo da variável object SEMPRE vai ser Object. Por esse motivo, acho que é impossível obter o tipo da variável que foi passada na chamada ao método, que era o que eu estava querendo.

Obrigado a todos e peço desculpas aos que possam ter ficado chateados com minha insistência. Mas foi porque eu não consegui nenhuma explicação plausível e não sossegaria até consegui-la.

[quote=RafaelVS]Depois que vi o código que postei acima, percebi que acho que não seja possível, mas não por algumas justificativas que li por aí, mas por causa do seguinte:

o que eu estava querendo era um METODO_MAGICO_DE_API_MAGICA(objeto); que fizesse o seguinte:

  1. se o objeto tiver instancia, entao retorna o tipo da instancia.
  2. se o objeto for null, entao retorna o tipo da variável.

Porém, se vc for imaginar como seria o corpo desse método, teríamos o seguinte:

Para atender a todos os casos, ele teria que ser ± assim (atenção na assinatura):

public static Class<?> METODO_MAGICO_DE_API_MAGICA(Object object){
   if(object != null){
      return object.getClass();
   }else{
      return //faz a mágina com object pra retornar o tipo da variável object.
   }
}

Porém, dentro desse método, o tipo da variável object SEMPRE vai ser Object. Por esse motivo, acho que é impossível obter o tipo da variável que foi passada na chamada ao método, que era o que eu estava querendo.

Obrigado a todos e peço desculpas aos que possam ter ficado chateados com minha insistência. Mas foi porque eu não consegui nenhuma explicação plausível e não sossegaria até consegui-la.[/quote]

Ok, mas so uma dúvida minha agora…
mesmo que vc conseguisse descobrir o tipo da variavel, no caso de ser null, de que lhe adiantaria se ainda assim vc nao poderia invocar nenhum metodo do objeto ? (NullPointerException)

[quote=SmartCardMan]
Ok, mas so uma dúvida minha agora…
mesmo que vc conseguisse descobrir o tipo da variavel, no caso de ser null, de que lhe adiantaria se ainda assim vc nao poderia invocar nenhum metodo do objeto ? (NullPointerException)[/quote]

Mas eu não queria descobrir o tipo da variável para chamar um método dessa variável. Eu queria saber o tipo da variável para eu poder informar ao método Class.getMethod(Class<?>[] tipoArgumentos, Object[] objetos); Esse método vai procurar na minha classe um método com a assinatura informada. Não vai invocá-lo. Tendo o metodo retornado, eu o invocaria passando um objeto não nulo sempre, podendo passar argumentos nulos, o que é normal em uma chamada de método.

Em códigos:

public class MinhaClasse{
   public Object meuMetodo(String parametro1, String parametro2){
      Object retorno = null;

      if(parametro2==null)
         { //legal, não faça nada com parametro2.}
      else
        { //bom, então vamos usar parametro1.}

      //faça algo com parametro1.
      //ajuste o retorno com um tempero especial.

      return retorno;
   }
}

//em outra classe, simplificando o código, a chamada seria:
public Object invocaMetodoComReflection(){
   String argumento1 = "valor";
   String argumento2 = null;

   //Note que eu preciso informar no segundo argumento os tipos das classes 
   //dos objetos que eu vou passar na hora de invocar.
   Method metodo = MinhaClasse.getMethod("meuMetodo", new Class<?>[]{String.class, String.class});

   //Aqui eu estou informando invocando 
   //passando uma instancia(ou seja, objeto não null) e os 
   //argumento1 e argumento2 (que é null)
   return metodo.invoke(new MinhaClasse(), new Object[]{argumento1, argumento2 });
}

   //Se eu pudesse garantir que na minha aplicação 
   //os objetos passados nunca seriam null, eu poderia 
   //centralizar as chamadas a API Reflection assim e 
   //vejam na assinatura do método que não preciso 
   //informar os tipos dos argumentos, o que simplificaria 
   //ainda mais a chamada:

public Object invocaMetodoSemArgumentosNull(Object objeto, String nomeMetodo, Object[] argumentoObjetos) 
   throws Exception {
     Class<?>[] argumentoClasses = new Class<?>[argumentoObjetos.length];
     for(int i = 0; i < argumentoObjetos.length; i++){
         //Se tivesse argumento null aqui daria NullPointerException
         argumentoClasses[i] = argumentoObjetos[i].getClass();
     }
     
     Method metodo = objeto.getClass().getMethod(nomeMetodo, argumentosClasses);
     return metodo.invoke(action, argumentosObjetos);
  }

   //Porém, já que não posso inferir o tipo da variável 
   //quando os argumentos são null, se algum argumento 
   //a ser passado para o método a ser invocado tem a 
   //possibilidade de ser null, então é preciso chamar 
   //usando esse método, ou seja, informando os 
   //tipos dos argumentos.

public Object invocaMetodoComEventuaisArgumentosNull(Object objeto, String nomeMetodo, 
   Class<?>[] argumentoClasses, Object[] argumentoObjetos) throws Exception {
     Method metodo = objeto.getClass().getMethod(nomeMetodo, argumentosClasses);
     return metodo.invoke(objeto, argumentosObjetos);
  }

   //A chamada então para invocação de métodos ficaria assim:

public static void main(String... args){
   MinhaClasse objeto = new MinhaClasse();
   String nomeMetodo = "meuMetodo";
   String argumento1 = "valor";
   String argumento2 = "valor";
   String argumento3 = nul;

   //Prepara chamada1:
   Object[] argumentosChamada1 = new Object[]{argumento1 , argumento2};
   //Agora a chamada, mais simples, não precisa de Class<?>[]. E era essa chamada
   //que eu queria que fosse feita, mesmo se os argumentos pudessem
   //ser null, mas isso só seria possível se, de alguma forma, dentro de
   //invocaMetodoSemArgumentosNull() eu pudesse descobrir o tipo da
   //variável que eu passei, mesmo quando essa fosse null. Mas o objeto
   //que invocaria a chamada não é null, pois esse é o argumento "objeto"
   //que estou passando na chamada ao método, como vemos abaixo:
   invocaMetodoSemArgumentosNull(objeto, nomeMetodo , argumentosChamada1);

   //Prepara chamada2:
   Class<?>[] tiposArgumentosChamada2 = new Class<?>[]{String.class, String.class};
   //Menos simples, precisa de Class<?>[], mas ainda assim é mais simples que diretamente à API Reflection.
   Object[] argumentosChamada2 = new Object[]{argumento2 , argumento3};
   invocaMetodoComEventuaisArgumentosNull(objeto, nomeMetodo, tiposArgumentosChamada2, argumentosChamada2);
}

Então, no final das contas o que eu queria era uma forma de descobrir o tipo da variável para poder as chamadas serem todas parecidas com a chamada1, onde não preciso informar diretamente o argumento Class<?>[].

ps.: eu escrevi o código acima diretamente daqui do forum, então pode ser que haja algum erro de compilação que tenha passado despercebido.

[quote=Aldrin Leal][quote=Sami Koivu]

  1. Os tipos de variáveis estão presentes para fins de debug opcionalmente, dependendo de opções de compilação. Nem sempre.
    [/quote]

Isto está contido no .class, independente das flags de compilação. Em debug, somente numeros de linha constam a mais.

Reflection é parte integrante do sistema.[/quote]

Olá,

Tipos de variáveis (que são definidos dentro de um bloco de código), diferentemente de campos (atributos) ou métodos de um classe não são disponíveis pela API de Reflection.

E essa informação nem sempre está disponível. Depende de flags de compilação, sim.

Mas, não acredite em mim, veja a especificação:

http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#5956

Você está certo em que os números de linha também são opcionalmente incluídos.

[]s,
Sami

Pessoal, o que é o cmando Class<?>[] ?? quando se usa isso?
e a classe Method é o q??

[quote=RaphaelSantos]Pessoal, o que é o cmando Class<?>[] ?? quando se usa isso?
e a classe Method é o q??[/quote]

I. Class<?>[] não é um comando. Vou explicar o que é por partes:

  1. Class é uma classe de Java, assim como String ou qualquer outra.
  2. Quando uso Class<?>, a parte <?> quer dizer que é um tipo genérico que herda de Object (vc pode pesquisar melhor sobre tipos genéricos se preferir se aprofundar)
  3. Quando coloco os colchetes, chegando finalmente a Class<?>[], estou me referenciando a um array de do tipo Class<?>, assim como vc declara arrays comuns, como int[].

Na discussão aqui a “expressão” Class<?>[] está sendo muito utilizada porque ela é o parâmetro de um método de uma classe em Java, da API Reflection (vc tb pode pesquisar sobre Reflection se preferir se aprofundar).

II. Method é uma classe da API Reflection e ela representa exatamente o que o nome indica, um método de uma classe java. Todo método que vc escreve nas suas classes podem ser lidos como um objeto do tipo Method. Para entender melhor, sugiro que vc estude a api Reflection.

Espero ter ajudado.

[]'s

Desculpe, compreendi errado, confundindo com o metadata da classe. Bem, exceto nos casos aonde temos obfuscators, sempre existe o ASM, certo? :slight_smile:

[quote=RafaelVS][quote=RaphaelSantos]Pessoal, o que é o cmando Class<?>[] ?? quando se usa isso?
e a classe Method é o q??[/quote]

I. Class<?>[] não é um comando. Vou explicar o que é por partes:

  1. Class é uma classe de Java, assim como String ou qualquer outra.
  2. Quando uso Class<?>, a parte <?> quer dizer que é um tipo genérico que herda de Object (vc pode pesquisar melhor sobre tipos genéricos se preferir se aprofundar)
  3. Quando coloco os colchetes, chegando finalmente a Class<?>[], estou me referenciando a um array de do tipo Class<?>, assim como vc declara arrays comuns, como int[].

Na discussão aqui a “expressão” Class<?>[] está sendo muito utilizada porque ela é o parâmetro de um método de uma classe em Java, da API Reflection (vc tb pode pesquisar sobre Reflection se preferir se aprofundar).

II. Method é uma classe da API Reflection e ela representa exatamente o que o nome indica, um método de uma classe java. Todo método que vc escreve nas suas classes podem ser lidos como um objeto do tipo Method. Para entender melhor, sugiro que vc estude a api Reflection.

Espero ter ajudado.

[]'s[/quote]
certo, entao quando vc usa Class<?> como parametro e vai usar o metodo, na parte que tem Class<?> quer dizer que é pra vc colocar uma classe nele?
e quando criamos metodos tipo
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
o que isso quer dizer???

onde posso arrumar informaçoes/tutoriais sobre uso/funcionamento/etc sobre reflection(que nao sejam em ingles)???

Class<?> é uma classe como outra qualquer, tem duas formas (pelo menos) de vc obter uma instancia de Classe<?>:

  1. a partir de um objeto, chamar objeto.getClass();
  2. NomeClasse.class;

Então, no codigo que vc colocou, o metodo retorna Class<?> e quando vc faz return String.classe vc ta retornando uma instancia de Class. A partir dessa instancia, vc pode ver acessar algumas informacoes da classe String, como nomes de metodos e pode ate invoca-los.

Material em português eu não conheco, mas quando eu comecei a estudar Reflection sobre perguntei aqui no GUJ e o VinliGodoy (acho que é esse o nome do usuario) me passou esse link, que foi suficiente pra eu fazer tudo que eu queria e mais um pouco (em ingles :frowning: ) :

http://java.sun.com/docs/books/tutorial/reflect/index.html