Pergunta

Eu preciso fazer algumas chamadas de método reflexivo em Java. Essas chamadas incluem métodos que possuem argumentos que são tipos primitivos (int, double, etc.). A maneira de especificar esses tipos quando se olha-se o método reflexivamente é int.class, double.class, etc.

O desafio é que eu estou aceitar a entrada de uma fonte externa que irá especificar os tipos dinamicamente. Portanto, eu preciso para chegar a estas referências de classe dinamicamente também. Imagine um arquivo delimitado uma lista de nomes de métodos com listas de tipos de parâmetros:

doSomething int double
doSomethingElse java.lang.String boolean

Se a entrada era algo como java.lang.String, eu sei que eu poderia usar Class.forName("java.lang.String") a essa Classe instância de volta. Existe alguma maneira de usar esse método, ou de outra, para obter as classes de tipo primitivo de volta?

Editar: Obrigado a todos os entrevistados. Parece claro que não há como built-in maneira de limpa fazer o que quero, por isso vou resolver para reutilizar a classe ClassUtils do framework Spring. Parece conter um substituto para Class.forName () que irá trabalhar com os meus requisitos.

Foi útil?

Solução

O framework Spring contém uma classe de utilitário ClassUtils que contém o método forName estática. Este método pode ser usado para a finalidade exata que você descreveu.

No caso de você não gosta de ter uma dependência em Primavera: o código-fonte do método pode ser encontrado e. g. aqui em seu repositório público. O código-fonte da classe está licenciado sob o modelo Apache 2.0.

Note, porém, que o algoritmo usa um mapa codificado de tipos primitivos.


Editar:. Graças a comentadores David Horvath e Patrick para apontar o link quebrado

Outras dicas

As instâncias Class para os tipos primitivos são obtidos como você disse usando, por exemplo int.class, mas também é possível obter os mesmos valores usando algo como Integer.TYPE. Cada classe empacotadora contém um campo estático, TYPE, que tem a instância da classe correspondente primitiva.

Você não pode obter a classe primitiva via forName, mas você pode obtê-lo a partir de uma classe que está prontamente disponível. Se você absolutamente deve usar a reflexão, você pode tentar algo como isto:

Class clazz = Class.forName("java.lang.Integer");
Class intClass = clazz.getField("TYPE").get(null);

intClass.equals(int.class);         // => true

Provavelmente você só precisa mapear os primitivos e para o resto das classes executar o método "forName":

eu faria algo como:

void someWhere(){
     String methodDescription = "doSomething int double java.lang.Integer java.lang.String"
     String [] parts = methodDescription.split();
     String methodName= parts[0]
     Class [] paramsTypes = getParamTypes( parts ); // Well, not all the array, but a, sub array from 1 to arr.length..  

    Method m = someObject.class.getMethod( methodName, paramTypes );
    etc. etc etc.
}

public Class[] paramTypes( String [] array ){
     List<Class> list = new ArrayList<Class>();
     for( String type : array ) {
         if( builtInMap.contains( type )) {
             list.add( builtInMap.get( type ) );
          }else{
             list.add( Class.forName( type ) );
          }
     }
     return list.toArray();
}  

    // That's right.
Map<String,Class> builtInMap = new HashMap<String,Class>();{
       builtInMap.put("int", Integer.TYPE );
       builtInMap.put("long", Long.TYPE );
       builtInMap.put("double", Double.TYPE );
       builtInMap.put("float", Float.TYPE );
       builtInMap.put("bool", Boolean.TYPE );
       builtInMap.put("char", Character.TYPE );
       builtInMap.put("byte", Byte.TYPE );
       builtInMap.put("void", Void.TYPE );
       builtInMap.put("short", Short.TYPE );
}

Isto é, criar um mapa onde os tipos primitivos são armazenados e se a descrição pertencem a uma primitiva, em seguida, usar a classe mapeada. Este mapa também pode ser carregado a partir de um arquivo de configuração externo, para adicionar flexibilidade para que você adicione String como um construído em vez de java.lang.String ou potencialmente ter método como este.

"doSomething sim cordas | não"

Há lotes deste tipo de código em projetos de Sistemas Operacionais, como libs Struts, Hibernate, Spring e Apache (só para citar alguns), para que você não precisa começar do zero.

BTW. Eu não compilar o código acima, mas eu tenho certeza que ele funciona com pequenas modificações não para baixo votar mim para isso.

Apache Commons Lang tem ClassUtils.getClass(String) , que suporta tipos de primitivas.

Uma série de métodos de classe não lidar com primitivas de uma forma consistente, infelizmente. Uma maneira comum em torno deste em forName é ter uma tabela como;

private static final Map<String, Class> BUILT_IN_MAP = 
    new ConcurrentHashMap<String, Class>();

static {
    for (Class c : new Class[]{void.class, boolean.class, byte.class, char.class,  
            short.class, int.class, float.class, double.class, long.class})
        BUILT_IN_MAP.put(c.getName(), c);
}

public static Class forName(String name) throws ClassNotFoundException {
    Class c = BUILT_IN_MAP.get(name);
    if (c == null)
        // assumes you have only one class loader!
        BUILT_IN_MAP.put(name, c = Class.forName(name));
    return c;
}

Os seguintes palestras de código sobre como obter a classe de um tipo primitivo cujo nome campo é conhecido, por exemplo, neste caso 'sampleInt'.

public class CheckPrimitve {
    public static void main(String[] args) {
        Sample s = new Sample();
        try {
            System.out.println(s.getClass().getField("sampleInt").getType() == int.class); // returns true
            System.out.println(s.getClass().getField("sampleInt").getType().isPrimitive()); // returns true
        } catch (NoSuchFieldException e) {          
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }       
    }
}

class Sample {
    public int sampleInt;
    public Sample() {
        sampleInt = 10;
    }
}

Pode-se também verificar se um determinado valor é primitivo ou não, obtendo sua respectiva classe de mensagens publicitárias ou do valor do campo.

    public class CheckPrimitve {
        public static void main(String[] args) {
            int i = 3;
            Object o = i;
            System.out.println(o.getClass().getSimpleName().equals("Integer")); // returns true
            Field[] fields = o.getClass().getFields();
            for(Field field:fields) {
                System.out.println(field.getType()); // returns {int, int, class java.lang.Class, int}
            }
        }
    }

O Google Guava ofertas com.google.common.primitives.Primitives para este tipo de coisa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top