2009-04-02 5 views
83

У меня есть массив Object[], и я пытаюсь найти примитивы. Я пытался использовать Class.isPrimitive(), но мне кажется, что я делаю что-то неправильно:Определение, является ли объект примитивным типом

int i = 3; 
Object o = i; 

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

отпечатки java.lang.Integer, false.

Есть ли правильный путь или альтернатива?

+6

isPrimitive() Короче говоря: 'междунар .class.isPrimitive() 'дает' true'; 'Integer.class.isPrimitive()' дает 'false'. – Patrick

ответ

141

Тип в Object[] никогда не будет действительно быть примитивным - потому что у вас есть ссылки! Здесь тип i равен int, тогда как тип объекта, на который ссылается o, составляет Integer (из-за автоматического бокса).

Похоже, вам нужно выяснить, является ли тип «оболочкой для примитива». Я не думаю, что есть что-то встроенные в стандартные библиотеки для этого, но это легко написать код:

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 Для домашнего решения. Я удалю мой :) –

+0

У меня создалось впечатление, что он действительно работал для примитивных оберток, но он работает только для 'java.lang. .TYPE', в конце концов, это, конечно, сам примитив. Кажется, я не смогу избежать проверки каждого типа отдельно, спасибо за хорошее решение. – drill3r

+3

Интересно, действительно ли накладные расходы на использование HashSet лучше, чем несколько операторов if. – NateS

6

Integer не является примитивным, Class.isPrimitive() не лжет.

8

Начиная с Java 1.5 и выше появилась новая функция, называемая авто-бокс. Компилятор делает это сам. Когда он видит возможность, он преобразует примитивный тип в соответствующий класс оболочки.

Что, вероятно, что здесь происходит, когда вы объявляете

Object o = i; 

компилятор компилирует это утверждение, как говорят

Object o = Integer.valueOf(i); 

Это авто-бокс. Это объясняет вывод, который вы получаете. This page from the Java 1.5 spec explains auto-boxing more in detail.

+4

Не совсем верно. Он не является новым Integer, а вызывает Integer.valueOf (int), который выполняет некоторое кэширование экземпляров Integer. –

+0

О, это очень верно. Спасибо за прояснение! –

4

Я думаю, что это происходит из-за авто-бокс.

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

Вы можете реализовать метод утилиты, соответствующий этим конкретным классам бокса, и дает вам, если определенный класс является примитивным.

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

Мне нравится этот ответ лучше всего, потому что он должен быть быстрее, чем поиск хэша. В памяти также есть еще один HashSet (предоставляется, что, вероятно, не так много). Наконец, люди могут оптимизировать это дальше, заказывая классы, по которым они воспринимаются как более частые. Это будет отличаться в каждом приложении. – bmauter

+3

Вы можете безопасно изменить '.equals' на' == '. Классы - это одноточие. – Boann

5

Вы должны иметь дело с авто-боксом java.
Возьмем код

public class test 
{ 
    public static void main(String [ ] args) 
    { 
     int i = 3; 
     Object o = i; 
     return; 
    } 
}
Вы получаете класс test.class и javap -c test давайте проверим сгенерированный байт-код.
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

}

Как вы можете видеть, что Java компилятор добавил
invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
создать новый Integer от ИНТА, а затем сохраняет , что новый объект в о с помощью astore_2

2

Как несколько людей уже сказали, это связанно с autoboxing.

Вы мог создать служебный метод для проверки того, класс объекта является Integer, Double и т.д. Но нет никакого способа узнать, был ли объект, созданный Autoboxing примитивного; как только он помещается в коробку, он выглядит точно так же, как объект, созданный явно.

Поэтому, если вы точно не знаете, что ваш массив никогда не будет содержать класс-оболочку без autoboxing, нет реального решения.

3

Точно так же вы можете видеть, что это возможно для isPrimitive вернуть истинный (поскольку у вас есть достаточное количество ответов, показывающих, почему это ложь):

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

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

Это имеет значение в отражении, когда метод принимает в «междунар ", а не" Integer ".

Этот код работает:

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) 
    { 
    } 
} 

Этот код не удается (не может найти метод):

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

В primitve типы оболочек не будет реагировать на это значение. Это для классового представления примитивов, хотя, помимо отражения, я не могу думать о слишком большом использовании для него. Так, например

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

печатает "ложные", но

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; 
} 

печатает "истинные"

15

Для тех, кто любит лаконичный код.

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

Почему Void.class? Как вы обертываете пустоту? –

+2

@Shervin 'void.class.isPrimitive()' возвращает true – assylias

+1

Void пуст, и единственным допустимым значением для 'Void' является' null';), это полезно для создания 'Callable ', который является Callable, который не работает Я ничего не верну. –

68

commons-langClassUtils имеет отношение методы. В новой версии:

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

Старые версии имеют wrapperToPrimitive(clazz) метод, который будет возвращать примитивный корреспонденцию. Так что вы можете сделать:

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

Это не было [добавлено до версии v3.1] (https://issues.apache.org/jira/browse/LANG-756), ваша ссылка отразила API 2.5. Я исправил это. – javamonkey79

+6

+1 для не изобретать колесо ... – Rob

+7

Весна также имеет [ClassUtils] (http: //docs.spring.io/spring/docs/3.1.4.RELEASE/javadoc-api/org/springframework/util/ClassUtils.html # isPrimitiveOrWrapper (java.lang.Class)), поэтому, если вы уже используете Spring, это может быть более удобно. – 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

Это самый простой способ, о котором я мог думать. Классы-оболочки присутствуют только в пакете java.lang. И кроме классов-оболочек, ни один другой класс в java.lang имеет поле с именем TYPE. Вы можете использовать это, чтобы проверить, является ли класс классом Wrapper или нет.

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

Это очень хрупкий и может быть неудачным в любое время в будущем ... – assylias

+1

Согласен. Но на данный момент это самый простой способ, о котором я мог думать. :) –

0

Я опаздываю на шоу, но если вы тестируете поле, вы можете использовать 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)); 
    } 
} 

Oracle docs список 8 примитивных типов.

0

можно определить, является ли объект обертку типа по ниже утверждений:

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

и вы можете также определить, примитивный объект с помощью метода

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; 
} 
Смежные вопросы