Dúvida em novo warning do Eclipse 3.2 (Java 5, varargs e argumento null)

4 respostas
Alexandre_Gazola

Pessoal,

o seguinte código:

1.Class x {public int[] getContents() { return new int[]{1,2,3};}

2.

3.Class cls = Class.forName(x);

4.Method meth = cls.getMethod(getContents, null);

O Eclipse informa esse warning relativo a linha 4:

“The argument of type null should explicitly be cast to Class[] for the invocation of the varargs method getMethod(String, Class…) from type Class. It could alternatively be cast to Class for a varargs invocation”

Tipo, pelo fato de o método getMethod da classe Class ter essa assinatura: public Method getMethod(String name, Class… parameterTypes), com o segundo parâmetro sendo do tipo varargs, não seria aconselhável eu passar simplesmente um null. O certo seria eu fazer

Method meth = cls.getMethod(“getContents”, (Class[]) null); ou
Method meth = cls.getMethod(“getContents”, (Class) null);

Mas eu não entendi porque isso é recomendável!

Alguém pode dar algum esclarecimento?

Obrigado

4 Respostas

T

No seu caso, você deveria passar (estilo antigo, e mais compreensível):

cls.getMethod ("getContents", new Class[]{})

ou

cls.getMethod ("getContents", new Class[0])

uma vez que você está indicando a getMethod que quer um método "getContents" que não tenha argumentos.

Segundo o JavaDoc de getMethod, é possível passar "null" para indicar um array vazio. Só que qual null?
Passar (Class)null tem o efeito de passar um array de Class com exatamente 1 elemento (null).
Passar (Class[])null tem o efeito desejado no JavaDoc, ou seja, passar um null que é um array de Class.

Eu passaria "new Class[0]" embora isso requeira a criação de um objeto, porque também pode ser "back-ported" para versões mais antigas do Java.
O que é muito mais simples, no entanto, é não passar nada; isso equivale a passar new Class[0].

import java.lang.reflect.*;

class TesteGetMethod {
    public static void main(String[] args) throws NoSuchMethodException{
        Method m;
        // Chamada compatível com JDK <= 1.4
// iconst_0
// anewarray       #4; //class java/lang/Class
// invokevirtual   #5; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;        
        m = TesteGetMethod.class.getMethod ("main", new Class[0]);
        // O código a seguir provoca um "warning" e é intencionalmente ambíguo
        // Não deve ser usado
// aconst_null
// invokevirtual   #5; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;        
        m = TesteGetMethod.class.getMethod ("main", null);
        // Note que este cast é equivalente a:
        // m = TesteGetMethod.class.getMethod ("main", new Class[]{(Class) null});
        // ou seja, não é o que está escrito na documentação.
// iconst_1
// anewarray       #4; //class java/lang/Class
// dup
// iconst_0
// aconst_null
// checkcast       #4; //class java/lang/Class
// aastore
// invokevirtual   #5; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        m = TesteGetMethod.class.getMethod ("main", (Class) null);
// ldc_w   #2; //class TesteGetMethod
// ldc     #3; //String main
// aconst_null
// checkcast       #6; //class "[Ljava/lang/Class;"
// invokevirtual   #5; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;        
        // Provavelmente é isto que a documentação sugere, se você não passar nada
        m = TesteGetMethod.class.getMethod ("main", (Class[]) null);
        // Como é varargs, você pode passar ZERO parâmetros se não for ambíguo. 
        // Neste caso é equivalente a passar new Class[0].
// iconst_0
// anewarray       #4; //class java/lang/Class
// invokevirtual   #5; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;        
        m = TesteGetMethod.class.getMethod ("main");
        
    }
}
Alexandre_Gazola

Eu só nao entendi ainda qual é o perigo de se passar null como argumento para um parâmetro varargs… Passar null para um método que receba um array é permitido sem nenhum problema.

Outro esclarecimento:
getMethod(“xxx”, new Class[0]) é exatamente igual a getMethod(“xxx”, (Class[]) null) ???

No Java antigo, ambos funcionam.

T

a) null para varargs é intrinsecamente ambíguo - se houver vários métodos com assinaturas diferentes - tanto é que o código que o javac gerou manifesta isso.
b) new Class[0] é um objeto do tipo Class[], enquanto (Class[]) null é um objeto null, que como sabemos pertence a todas as classes.
No Java antigo, ambos funcionam porque o Javadoc de getMethod diz explicitamente isso - ou seja, que “null” é aceito como parâmetro; se você definisse o seu próprio método com varargs, provavelmente você teria problemas.

T

Não tenho a nova versão do “Effective Java”, mas provavelmente isso (que é um novo warning que também aparece com o javac da versão 6.0 - Mustang) é algo que deve ser visto.
(Acho que essa é uma “ponta solta” que deixaram na especificação).

Criado 10 de julho de 2006
Ultima resposta 11 de jul. de 2006
Respostas 4
Participantes 2