2009-04-02 14 views
83

Tengo una matriz Object[], y estoy tratando de encontrar las que son primitivas. He tratado de utilizar Class.isPrimitive(), pero parece que estoy haciendo algo mal:Determinando si un Objeto es del tipo primitivo

int i = 3; 
Object o = i; 

System.out.println(o.getClass().getName() + ", " + 
        o.getClass().isPrimitive()); 

impresiones java.lang.Integer, false.

¿Hay una manera correcta o una alternativa?

+6

En pocas palabras: 'int .class.isPrimitive() 'produce' true'; 'Integer.class.isPrimitive()' produce 'false'. – Patrick

Respuesta

141

Los tipos en un Object[] nunca realmente ser primitivo - ¡porque usted tiene referencias! Aquí el tipo de i es int, mientras que el tipo del objeto al que hace referencia o es Integer (debido al auto-boxing).

Parece que necesita averiguar si el tipo es "envoltorio para primitivo". No creo que haya nada incorporado en las bibliotecas estándar para esto, pero es fácil de codificar hasta:

import java.util.*; 

public class Test 
{ 
    public static void main(String[] args)   
    { 
     System.out.println(isWrapperType(String.class)); 
     System.out.println(isWrapperType(Integer.class)); 
    } 

    private static final Set<Class<?>> WRAPPER_TYPES = getWrapperTypes(); 

    public static boolean isWrapperType(Class<?> clazz) 
    { 
     return WRAPPER_TYPES.contains(clazz); 
    } 

    private static Set<Class<?>> getWrapperTypes() 
    { 
     Set<Class<?>> ret = new HashSet<Class<?>>(); 
     ret.add(Boolean.class); 
     ret.add(Character.class); 
     ret.add(Byte.class); 
     ret.add(Short.class); 
     ret.add(Integer.class); 
     ret.add(Long.class); 
     ret.add(Float.class); 
     ret.add(Double.class); 
     ret.add(Void.class); 
     return ret; 
    } 
} 
+6

+1 Para una solución local. Eliminaré el mío :) –

+0

Tenía la impresión de que funcionaba para las envolturas primitivas, pero solo funciona para 'java.lang. .TYPE' después de todo, que por supuesto es el primitivo en sí mismo. Parece que no podré evitar buscar cada tipo individualmente, gracias por la buena solución. – drill3r

+3

Me pregunto si la sobrecarga de usar HashSet es realmente mejor que unas pocas sentencias if. – NateS

6

Integer no es un primitivo, Class.isPrimitive() no está mintiendo.

8

A partir de Java 1.5 y posteriores, hay una nueva característica llamada auto-boxing. El compilador hace esto por sí mismo. Cuando ve una oportunidad, convierte un tipo primitivo en su clase contenedora apropiada.

Probablemente lo que ocurre aquí es cuando se declara

Object o = i; 

El compilador compilará esta declaración diciendo

Object o = Integer.valueOf(i); 

Esto es auto-boxing. Esto explicaría el resultado que está recibiendo. This page from the Java 1.5 spec explains auto-boxing more in detail.

+4

No es totalmente cierto. No es nuevo un Entero, sino que llama a Integer.valueOf (int) que hace algo de almacenamiento en caché de las instancias de Entero. –

+0

Oh, eso es muy cierto. Gracias por el aclaramiento! –

4

Creo que esto sucede debido a auto-boxing.

int i = 3; 
Object o = i; 
o.getClass().getName(); // prints Integer 

Puede implementar un método de utilidad que coincida con estas clases de boxeo específicas y le proporciona si una cierta clase es primitiva.

public static boolean isWrapperType(Class<?> clazz) { 
    return clazz.equals(Boolean.class) || 
     clazz.equals(Integer.class) || 
     clazz.equals(Character.class) || 
     clazz.equals(Byte.class) || 
     clazz.equals(Short.class) || 
     clazz.equals(Double.class) || 
     clazz.equals(Long.class) || 
     clazz.equals(Float.class); 
} 
+0

Me gusta esta respuesta mejor porque debería ser más rápida que una búsqueda hash. También hay un HashSet menos en memoria (dado que probablemente no sea mucho). Por último, la gente podría optimizar esto más al ordenar las clases por las cuales se perciben como más frecuentes. Eso será diferente en cada aplicación. – bmauter

+3

Puede cambiar '.equals' de forma segura a' == '. Las clases son singletons. – Boann

5

Tienes que lidiar con el auto-boxing de java.
Tomemos el código

public class test 
{ 
    public static void main(String [ ] args) 
    { 
     int i = 3; 
     Object o = i; 
     return; 
    } 
}
Obtendrá la clase test.class y javap -c test le permitiremos inspeccionar el bytecode generado.
Compiled from "test.java" 
public class test extends java.lang.Object{ 
public test(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."":()V 
    4: return

public static void main(java.lang.String[]); Code: 0: iconst_3 1: istore_1 2: iload_1 3: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 6: astore_2 7: return

}

Como se puede ver el compilador Java añade
invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
para crear un nuevo número entero de su int y la almacena ese nuevo objeto en O a través de astore_2

2

Como varias personas ya han dicho, esto se debe a autoboxing.

Usted podría crear un método de utilidad para comprobar si la clase del objeto es Integer, Double, etc. Pero hay hay manera de saber si un objeto fue creado por autoboxing una primitiva; una vez que está encuadrado, se ve como un objeto creado explícitamente.

De modo que a menos que esté seguro de que su matriz nunca contendrá una clase contenedora sin autoboxing, no hay una solución real.

3

Sólo así se puede ver que es es posible que isPrimitive para volver verdadero (ya que usted tiene suficientes respuestas que muestran por qué es falso):

public class Main 
{ 
    public static void main(final String[] argv) 
    { 
     final Class clazz; 

     clazz = int.class; 
     System.out.println(clazz.isPrimitive()); 
    } 
} 

Esto importa en la reflexión cuando un método toma en "int "en lugar de un" Entero ".

Este código funciona: no

import java.lang.reflect.Method; 

public class Main 
{ 
    public static void main(final String[] argv) 
     throws Exception 
    { 
     final Method method; 

     method = Main.class.getDeclaredMethod("foo", int.class); 
    } 

    public static void foo(final int x) 
    { 
    } 
} 

Este código (no puede encontrar el método):

import java.lang.reflect.Method; 

public class Main 
{ 
    public static void main(final String[] argv) 
     throws Exception 
    { 
     final Method method; 

     method = Main.class.getDeclaredMethod("foo", Integer.class); 
    } 

    public static void foo(final int x) 
    { 
    } 
} 
2

Los tipos de envoltura primitve no responderán a este valor. Esto es para la representación de primitivos en clase, aunque aparte de la reflexión no puedo pensar en demasiados usos para ello. Así, por ejemplo

System.out.println(Integer.class.isPrimitive()); 

impresiones "falsos", pero

public static void main (String args[]) throws Exception 
{ 
    Method m = Junk.class.getMethod("a",null); 
    System.out.println(m.getReturnType().isPrimitive()); 
} 

public static int a() 
{ 
    return 1; 
} 

impresiones "verdaderos"

15

Para aquellos que gustan de código conciso.

private static final Set<Class> WRAPPER_TYPES = new HashSet(Arrays.asList(
    Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class)); 
public static boolean isWrapperType(Class clazz) { 
    return WRAPPER_TYPES.contains(clazz); 
} 
+1

¿Por qué Void.class? ¿Cómo envuelve un vacío? –

+2

@Shervin 'void.class.isPrimitive()' devuelve true – assylias

+1

El vacío está vacío y el único valor válido para un 'Void' es' null';) es útil para crear un 'Callable ' que es un invocable que doesn devuelve cualquier cosa –

68

commons-langClassUtils tiene métodos relevantes. La nueva versión tiene:

boolean isPrimitiveOrWrapped = 
    ClassUtils.isPrimitiveOrWrapper(object.getClass()); 

Las versiones antiguas tienen wrapperToPrimitive(clazz) método, que devolverá la primitiva correspondencia. Por lo que puede hacer:

boolean isPrimitiveOrWrapped = 
    clazz.isPrimitive() || ClassUtils.wrapperToPrimitive(clazz) != null; 
+0

Esto no era [añadido hasta v3.1] (https://issues.apache.org/jira/browse/LANG-756), su enlace refleja la API 2.5. Lo he corregido – javamonkey79

+6

1 para no reinventar la rueda ... – Rob

+7

primavera también tiene [ClassUtils] (http: //docs.spring.io/spring/docs/3.1.4.RELEASE/javadoc-api/org/springframework/util/ClassUtils.html # isPrimitiveOrWrapper (java.lang.Class) clase, por lo que si ya está utilizando Spring, puede ser más conveniente. – Sergey

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

Output: 
true 
int 
int 
class java.lang.Class 
int 
1

Esta es la manera más simple que se me ocurre. Las clases contenedoras están presentes solo en el paquete java.lang. Y aparte de las clases contenedoras, ninguna otra clase en java.lang tiene un campo llamado TYPE. Puede usar eso para verificar si una clase es clase Wrapper o no.

public static boolean isBoxingClass(Class<?> clazz) 
{ 
    String pack = clazz.getPackage().getName(); 
    if(!"java.lang".equals(pack)) 
     return false; 
    try 
    { 
     clazz.getField("TYPE"); 
    } 
    catch (NoSuchFieldException e) 
    { 
     return false; 
    }   
    return true;   
} 
+1

Eso es muy frágil y podría fallar en cualquier momento en el futuro ... – assylias

+1

Estoy de acuerdo. Pero a partir de ahora, es la manera más simple que se me ocurre. :) –

0

estoy tarde para el espectáculo, pero si se está probando un campo, puede utilizar getGenericType:

import static org.junit.Assert.*; 

import java.lang.reflect.Field; 
import java.lang.reflect.Type; 
import java.util.Arrays; 
import java.util.Collection; 
import java.util.HashSet; 

import org.junit.Test; 

public class PrimitiveVsObjectTest { 

    private static final Collection<String> PRIMITIVE_TYPES = 
      new HashSet<>(Arrays.asList("byte", "short", "int", "long", "float", "double", "boolean", "char")); 

    private static boolean isPrimitive(Type type) { 
     return PRIMITIVE_TYPES.contains(type.getTypeName()); 
    } 

    public int i1 = 34; 
    public Integer i2 = 34; 

    @Test 
    public void primitive_type() throws NoSuchFieldException, SecurityException { 
     Field i1Field = PrimitiveVsObjectTest.class.getField("i1"); 
     Type genericType1 = i1Field.getGenericType(); 
     assertEquals("int", genericType1.getTypeName()); 
     assertNotEquals("java.lang.Integer", genericType1.getTypeName()); 
     assertTrue(isPrimitive(genericType1)); 
    } 

    @Test 
    public void object_type() throws NoSuchFieldException, SecurityException { 
     Field i2Field = PrimitiveVsObjectTest.class.getField("i2"); 
     Type genericType2 = i2Field.getGenericType(); 
     assertEquals("java.lang.Integer", genericType2.getTypeName()); 
     assertNotEquals("int", genericType2.getTypeName()); 
     assertFalse(isPrimitive(genericType2)); 
    } 
} 

La lista Oracle docs los 8 tipos primitivos.

0

que podrían determinar si un objeto es Wrapper por debajo de declaraciones:

***objClass.isAssignableFrom(Number.class);*** 

y también se puede determinar un objeto primitivo utilizando el método isPrimitive()

1
public static boolean isValidType(Class<?> retType) 
{ 
    if (retType.isPrimitive() && retType != void.class) return true; 
    if (Number.class.isAssignableFrom(retType)) return true; 
    if (AbstractCode.class.isAssignableFrom(retType)) return true; 
    if (Boolean.class == retType) return true; 
    if (Character.class == retType) return true; 
    if (String.class == retType) return true; 
    if (Date.class.isAssignableFrom(retType)) return true; 
    if (byte[].class.isAssignableFrom(retType)) return true; 
    if (Enum.class.isAssignableFrom(retType)) return true; 
    return false; 
} 
Cuestiones relacionadas