객체가 기본 유형인지 확인


114

나는이 Object[]배열을, 나는 원시있는 사람을 찾기 위해 노력하고있다. 을 (를) 사용하려고했지만 Class.isPrimitive()뭔가 잘못하고있는 것 같습니다.

int i = 3;
Object o = i;

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

인쇄합니다 java.lang.Integer, false.

올바른 방법이나 대안이 있습니까?


12
요컨대 : int.class.isPrimitive()yields true; Integer.class.isPrimitive()수익률 false.
Patrick

답변:


165

의 종류는 Object[]않습니다 정말 원시적 수 없습니다 - 당신이 참조를 가지고 있기 때문에! 여기서의 유형은 iis 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;
    }
}

나는 그것이 원시 래퍼에 대해 작동한다는 인상을 받았지만 결국 java.lang.<type>.TYPE원시 자체 인 경우에만 작동 합니다. 좋은 솔루션 덕분에 각 유형을 개별적으로 확인하는 것을 피할 수 없을 것 같습니다.
drill3r 2009

3
HashSet을 사용하는 오버 헤드가 if 문 몇 개보다 정말 좋은지 궁금합니다.
NateS

9
@NateS : 더 읽기 쉽다고 믿습니다. 그래서 세트의 오버 헤드가 실제 병목 현상이라는 것이 증명 될 때까지 "if"문 대신에 그 문 을 사용합니다.
Jon Skeet

1
@mark : 그렇다면 그것은 매우 구체적인 맥락이며 그렇게 취급되어야합니다. 오토 박싱이 열거 형에 적용됩니까? 아니요, 이미 참조 유형입니다. 널 불가능합니까? 아니요, 참조 유형이기 때문에 ... 목록은 계속됩니다. 그것들을 프리미티브라고 부르는 것은 그 용어의 의미를 크게 약화시키고, 나는 그것에 대한 이점을 보지 못합니다.
Jon Skeet 2013 년

2
@NateS HashSet는 O (1)에서 액세스를 허용하는 반면 if문 또는 문 행은 switch최악의 경우 O (래퍼 수)가 필요합니다. 실제로 if고정 된 수의 9 개 래퍼에 대한 문이 결국 해시 기반 액세스보다 빠르지 않은지 의심 스럽다 .
Karl Richter

83

commons-lang ClassUtils 에는 관련 메서드가 있습니다.

새 버전에는 다음이 포함됩니다.

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

이전 버전에는 기본 대응 wrapperToPrimitive(clazz)을 반환하는 메서드가 있습니다.

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

1
이것은 v3.1까지 추가 되지 않았으며 링크에 2.5 API가 반영되었습니다. 나는 그것을 고쳤다.
javamonkey79

8
Spring에는 ClassUtils 클래스도 있으므로 이미 Spring을 사용하고 있다면 더 편리 할 수 ​​있습니다.
Sergey


17

간결한 코드를 좋아하는 사람들을 위해.

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인가? 보이드를 어떻게 감싸나요?
Shervin 아스 가리

2
@Shervin void.class.isPrimitive()진정한 수익을
assylias은

1
Void는 비어 있고 a에 대한 유일한 유효한 값 Voidnull;) Callable<Void>아무것도 반환하지 않는 Callable 을 만드는 데 유용합니다 .
피터 Lawrey

8

Java 1.5 이상부터는 자동 박싱이라는 새로운 기능이 있습니다. 컴파일러가이 작업을 수행합니다. 기회를 발견하면 기본 유형을 적절한 래퍼 클래스로 변환합니다.

아마도 여기서 일어나는 일은

Object o = i;

컴파일러는이 문장을 다음과 같이 컴파일합니다.

Object o = Integer.valueOf(i);

이것은 자동 권투입니다. 이것은 당신이 받고있는 출력을 설명 할 것입니다. Java 1.5 사양의이 페이지에서는 자동 박싱에 대해 자세히 설명합니다.


6
완전히 사실이 아닙니다. 새로운 Integer가 아니라 Integer 인스턴스의 일부 캐싱을 수행하는 Integer.valueOf (int)를 호출합니다.
Steve Kuo

1
@SteveKuo Integer.valueOf(int)자체는 인수가 "바이트"인 경우에만 캐시 된 값을 반환합니다 (읽기 : -128, 127, 둘 다 포함). 그렇지 않으면 new Integer(int). 참조 : developer.classpath.org/doc/java/lang/… , hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/…
Dragas

6

Integer원시적 Class.isPrimitive()이지 않고 거짓말이 아닙니다.


6

나는 이것이 자동 복싱 때문이라고 생각합니다 .

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

해시 조회보다 빠르기 때문에이 답변이 가장 좋습니다. 또한 메모리에 HashSet이 하나 적습니다 (아마 많지 않을 수 있음). 마지막으로, 사람들은 더 빈번하게 인식되는 클래스를 정렬하여이를 더욱 최적화 할 수 있습니다. 그것은 모든 응용 프로그램에서 다를 것입니다.
bmauter 2014 년

5
안전하게 변경할 수 있습니다 .equals==. 클래스는 싱글 톤입니다.
Boann 2014

5

자바의 자동 복싱을 처리해야합니다.
코드를 가져 가자

공개 수업 시험
{
    public static void main (String [] args)
    {
        int i = 3;
        객체 o = i;
        반환;
    }
}
test.class 클래스와 javap -c test를 받으면 생성 된 바이트 코드를 검사 할 수 있습니다.
"test.java"에서 컴파일 됨
공용 클래스 테스트는 java.lang.Object {를 확장합니다.
공개 테스트 ();
  암호:
   0 : aload_0
   1 : invokespecial # 1; // 메소드 java / lang / Object. "":() V
   4 : 반환

public static void main (java.lang.String []); 암호: 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 : 반환

}

보시다시피 Java 컴파일러가 추가되었습니다.
invokestatic # 2; // Method java / lang / Integer.valueOf : (I) Ljava / lang / Integer;
int에서 새 Integer를 만든 다음 astore_2를 통해 o에 새 Object 를 저장 합니다.


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

3

isPrimitive가 true를 반환하는 것이 가능하다는 것을 알 수 있습니다 (거짓 이유를 보여주는 충분한 답변이 있기 때문에).

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

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

이것은 메서드가 "Integer"가 아닌 "int"를 사용할 때 반영됩니다.

이 코드는 다음과 같이 작동합니다.

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

여러 사람들이 이미 말했듯이 이것은 오토 박싱 때문 입니다.

당신은 수있는 객체의 클래스인지 여부를 확인하는 유틸리티 메소드를 작성 Integer, Double등,하지만이없는 오브젝트가 원시적를 오토 박싱에 의해 만들어 졌는지 여부를 알 수있는 방법이 ; 박스에 넣으면 명시 적으로 생성 된 객체처럼 보입니다.

따라서 배열에 오토 박싱 없이는 래퍼 클래스가 포함되지 않는다는 것을 확실히 알지 못하면 실제 솔루션이 없습니다.


2

primitve 래퍼 유형은이 값에 응답하지 않습니다. 이것은 프리미티브의 클래스 표현을위한 것이지만, 리플렉션을 제외하고는 너무 많이 사용한다고 생각할 수는 없습니다. 예를 들어

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

"false"를 인쇄하지만

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

"true"를 인쇄합니다.


2

나는 쇼에 늦었지만 필드를 테스트하는 경우 다음을 사용할 수 있습니다 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));
    }
}

오라클 문서는 8 개 기본 유형을 나열합니다.


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
나는 동의한다. 하지만 지금은 제가 생각할 수있는 가장 간단한 방법입니다. :)
Rahul Bobhate 2013 년


1

문 아래에서 객체가 래퍼 유형인지 확인할 수 있습니다.

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

isPrimitive () 메서드를 사용하여 기본 객체를 결정할 수도 있습니다.


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

0

javapoet 사용자에게는 다음과 같은 방법도 있습니다.

private boolean isBoxedPrimitive(Class<?> type) {
    return TypeName.get(type).isBoxedPrimitive();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.