オブジェクトがプリミティブ型かどうかの判別


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 14

回答:


165

の型Object[]本当にプリミティブになることありませ -参照があるからです!ここでは、のタイプはiisですintが、によって参照されるオブジェクトのタイプoInteger(自動ボックス化のため)です。

タイプが「プリミティブのラッパー」であるかどうかを調べる必要があるようです。これのために標準ライブラリに組み込まれているものはないと思いますが、簡単にコーディングできます。

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、2011

9
@NateS:私はそれがより読みやすいと信じています。そのため、セットのオーバーヘッドが実際のボトルネックであることが証明されるまで、「if」ステートメントの代わりにそれを使います。
Jon Skeet、

1
@マーク:それはそれは非常に特定のコンテキストであり、そのように扱われるべきです。オートボクシングは列挙型に適用されますか?いいえ、それらはすでに参照型です。非ヌル可能ですか?いいえ、それらは参照型なので...リストは続きます。それらをプリミティブと呼ぶと、用語の意味が大幅に弱まり、私にはその利点がわかりません。
Jon Skeet 2013年

2
@NateS HashSetはO(1)でのアクセスを許可しますが、最悪の場合ifswitchステートメントの行またはステートメントは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 2012

8
SpringにはClassUtilsクラスもあるので、すでにSpringを使用している場合はより便利です。
セルゲイ


16

簡潔なコードが好きな人のために。

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 Asgari、2011

2
@Shervin void.class.isPrimitive()はtrueを返します
アサイリア

1
Voidは空で、aの唯一の有効な値Voidnull;)です。Callable<Void>これは、何も返さないCallableであるa を作成する場合に役立ちます。
Peter Lawrey、

8

Java 1.5以降では、オートボクシングと呼ばれる新機能があります。コンパイラはこれを自分で行います。機会を見つけると、プリミティブ型を適切なラッパークラスに変換します。

おそらくここで起こっているのは宣言するときです

Object o = i;

コンパイラはこのステートメントを次のようにコンパイルします

Object o = Integer.valueOf(i);

これはオートボクシングです。これは、受け取っている出力を説明します。Java 1.5仕様のこのページでは、自動ボックス化について詳しく説明しています。


6
まったくそうではありません。Integerを新しく作成するのではなく、Integerインスタンスのキャッシュを行うInteger.valueOf(int)を呼び出します。
スティーブクオ

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は1つ少なくなります(おそらくそれほど多くないことを認めています)。最後に、クラスがより頻繁であると認識されるクラスを順序付けることで、これをさらに最適化できます。それはすべてのアプリケーションで異なります。
bmauter 2014年

5
あなたは安全に変更することができます.equals==。クラスはシングルトンです。
Boann、2014

5

Javaの自動ボクシングに対処する必要があります。
コードを見てみましょう

パブリッククラステスト
{
    public static void main(String [] args)
    {
        int i = 3;
        オブジェクトo = i;
        戻る;
    }
}
クラスtest.classとjavap -c testを取得すると、生成されたバイトコードを検査できます。
「test.java」からコンパイル
public class testはjava.lang.Object {を拡張します
public test();
  コード:
   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; //メソッドjava / lang / Integer.valueOf:(I)Ljava / lang / Integer; 6:astore_2 7:戻る

}

あなたが見ることができるように追加されたJavaコンパイラ
invokestatic#2; //メソッドjava / lang / Integer.valueOf:(I)Ljava / lang / Integer;
intから新しいIntegerを作成し、astore_2を介してoにその新しいオブジェクトを格納ます


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を返すことが可能であることを確認できるように(これがfalseである理由を示す十分な回答があるため):

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

すでにいくつかの人が言っているように、これはオートボクシングによるものです。

あなたは可能性があり、オブジェクトのクラスがあるかどうかを確認するためのユーティリティメソッドを作成IntegerDoubleなど、しかし、存在しないオブジェクトは、プリミティブをオートボクシングによって作成されたかどうかを知る方法は、ボックス化されると、明示的に作成されたオブジェクトのように見えます。

したがって、配列にオートボクシングなしのラッパークラスが含まれないことが確実にわかっていない限り、実際の解決策はありません。


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

Oracleのドキュメントは 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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.