38

I have a piece of code where I need to pass the class of a field in a method. Because of the mechanics of my code I can only handle reference objects and not primitives. I want an easy way of determining if a Field's type is primitive and swap it with the appropriate wrapper class. So in code what I do so far is something like this:

Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
if (c == int.class) {
    c = Integer.class;
}
else if (c == float.class) {
    c = Float.class;
}
// etc
myMethod(c);

This works fine, except for the fact that I need to explicitly check for all the primitive types and swap them with the appropriate wrapper class. Now I know that there are not so many primitive types and it won't be a problem to simply list them all, but I was wondering if there was an easier and more elegant way of doing it.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Savvas Dalkitsis
  • 11,476
  • 16
  • 65
  • 104

8 Answers8

47

Apache Commons Lang has a utility method to do this (ClassUtils.primitiveToWrapper()), which will be just as ugly under the covers, but at least you can pretend it's nice.

skaffman
  • 398,947
  • 96
  • 818
  • 769
46

I think this answer is probably the right way now

Or, Guava has this:

http://google.github.io/guava/releases/21.0/api/docs/com/google/common/primitives/Primitives.html

It has the wrap() method, plus unwrap() and a few other incidental things.

If you don't use Guava, you can follow the example of its implementation.

Kevin Bourrillion
  • 40,336
  • 12
  • 74
  • 87
22

Here is another way if you don't need highly optimized code:

    Class<?> primitive=long.class;
    Class<?> boxed=Array.get(Array.newInstance(primitive,1),0).getClass();
    System.out.println(primitive.getName());
    System.out.println(boxed.getName());

(Editing/adding explanation)

At first, it was to see if Java has a method to give you the wrapper class when given a primitive type. Couldn't find any.

Then, it was to see if you can have Java create a primitive value when give a primitive type (then you can somehow get an object out of it). Couldn't find a way to do this.

But then it was found out that you CAN have Java create an array of primitive values when given a primitive type. And then there is a Java method that gives you an object of the wrapping type of the array element(which is primitive). Once you have the object, you can then get the type.

So here is how the whole thing work:

The method Array.newInstance() creates a array of whatever type you specify, whether it is primitive or object. In the case of object, all elements are object type but initialized to null. In the case of primitive, elements are primitive type. But primitive variable/array element can't be null, so they have the default value of the primitive type, e.g. int will be zero. Thus no elements will be null. And now if you try to get the value of an element by using Array.get(), Array.get() has no choice but box that primitive value to an object, e.g. int to Integer, because Array.get() can't return primitive value. Now you have an object of the boxing(wrapping) type of you original primitive type. Finally calling Object.getClass() gives you the boxing(wrapping) type.

This trick works with any primitive type you have in Java today and in the future.

Fai Ng
  • 760
  • 1
  • 6
  • 14
8

You can call class.isPrimitive() to know if it is a primitive or not, however, there is no boxing method to convert the classes within the JDK. There is at least one open bug relating to this.

Yishai
  • 90,445
  • 31
  • 189
  • 263
  • There are also fields in the wrapper classes which will let you get to the primitive classes (e.g., `Double.TYPE` is the same as `double.class`), but there's no non-ugly way to take advantage of that programmatically. – Ti Strga Apr 20 '17 at 19:13
7

Since Java 7, this is a one-liner:

@SuppressWarnings("unchecked")
public static <T> Class<T> wrap(Class<T> c) {
    return (Class<T>) MethodType.methodType(c).wrap().returnType();
}

@SuppressWarnings("unchecked")
public static <T> Class<T> unwrap(Class<T> c) {
    return (Class<T>) MethodType.methodType(c).unwrap().returnType();
}

Here is a test that I wrote using JMH and here are the results:

Benchmark                        Mode  Cnt   Score   Error  Units
PrimitiveToWrapper.ifStatements  avgt   30  42.112 ± 0.716  ns/op
PrimitiveToWrapper.map           avgt   30  45.018 ± 0.923  ns/op
PrimitiveToWrapper.wrap          avgt   30  52.369 ± 0.836  ns/op

The difference is rather small.

Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • The behaviour of this method is not the same as the needed in the question. Also, nested `if`statements will be more efficient! – LSafer Aug 01 '20 at 22:43
  • 1
    @LSaferSE of course your statements are based on facts, right? Facts that I could check and you can provide examples of? – Eugene Aug 02 '20 at 03:07
  • yes, `if` statements are way more efficient, but the behaviour may change since the methods isn't made for that purpose. – LSafer Aug 03 '20 at 05:19
  • 1
    @LSafer what actual _arguments_ you have for 1) "more efficient" 2) "isn't made for that purpose"? – Eugene Sep 17 '20 at 15:06
  • It is more efficient since the above method is just a fancy wrapping over multiple `if` statements. So, direct `if` statement will be more efficient since no additional methods and asserts will be done. – LSafer Nov 12 '20 at 07:51
  • I forgot the complete context. But, I remember that it was part of a dynamic reflection system. So, it has been made for that system not just as a utility. It is a utility specified for that system. – LSafer Nov 12 '20 at 07:55
  • 1
    @LSafer when I said arguments, I did not mean plain words, but numbers; especially on the "efficient" part and especially on your "if vs map", as such, see the edit. – Eugene Nov 12 '20 at 19:32
  • I got no time for you. Sorry! Think about it yourself. How does Maps work? How does key finding work? anyway unless it is in another language via a proxy. Or via some AI. 'if' statements will remain the core solution for this. Unwrapping 'if' statements will be the more efficient way since no redundant pushes to the stack frame will be made! – LSafer Nov 13 '20 at 20:15
  • The opposite of that (wrapper class to primitive) will be much easier and require no if statements. Since all wrapper classes has a static public field for their primitive class. I think it has the name 'TYPE' – LSafer Nov 13 '20 at 20:19
  • I just realized you wrote the benchmark is similar. When building a library. Or building any large scale program. Each millisecond count! In theory, there should be a huge difference, but it might be some optimizations have been made so that stackframe pushes be more lighter – LSafer Nov 13 '20 at 20:25
  • 1
    I'm surprised this answer received so few upvotes. It's a simple and concise solution that doesn't require any additional libraries. The efficiency/performance and philosophical questions aside, I can't quite understand previous comments stating that the "behaviour of this method is not the same as the needed in the question" - AFAICT, `MethodType.wrap()` does correctly convert all 8 primitives and `void` into their corresponding wrapper classes, and leaves all other types unchanged. – raner Apr 09 '22 at 08:17
  • 1
    I have to say there was so little reason to suspect a significant performance problem that it's sad that @Eugene was baited into having to write a whole benchmark for it. "Each millisecond count!" is not a good argument, especially when it would take 100,000 calls to this method to add up to a difference of 1 millisecond. – Kevin Bourrillion Nov 12 '22 at 19:29
  • 1
    And re: "The opposite of that (wrapper class to primitive) will be much easier and require no if statements. Since all wrapper classes has a static public field for their primitive class." You seemed to be extremely concerned about nano-optimization and then you recommended a solution based on *reflection*. – Kevin Bourrillion Nov 12 '22 at 19:30
  • Thanks for this tidbit. Javadoc of `java.lang.invoke.MethodType` mentions `@since 1.7` then it can be used even sooner. – bjmi Nov 13 '22 at 07:39
4
Class<?> toWrapper(Class<?> clazz) {
    if (!clazz.isPrimitive())
        return clazz;

    if (clazz == Integer.TYPE)
        return Integer.class;
    if (clazz == Long.TYPE)
        return Long.class;
    if (clazz == Boolean.TYPE)
        return Boolean.class;
    if (clazz == Byte.TYPE)
        return Byte.class;
    if (clazz == Character.TYPE)
        return Character.class;
    if (clazz == Float.TYPE)
        return Float.class;
    if (clazz == Double.TYPE)
        return Double.class;
    if (clazz == Short.TYPE)
        return Short.class;
    if (clazz == Void.TYPE)
        return Void.class;

    return clazz;
}
Jim Smith
  • 61
  • 2
  • This is a very old answer, but effective, just copy & paste, and don't have to use other libraries just to do this. – n3k0 Nov 23 '18 at 20:30
3

So you want to get the wrapper class type, ok.

No need to query the types or reference look up tables because java already does it anyway. Let's walk through the problem together...

Synopsis

We are retrieving a field and then find it contains a primitive type.

Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType(); // Gets the declared primitive type

But instead we want the wrapper type.

Primitive types in Java

Now as you already found out the only thing a primitive class is good for is to return true for c.isPrimitive();.

From wiki books - java programming:

Primitive types are the most basic data types available within the Java language. There are 8: boolean , byte , char , short , int , long , float and double . These types serve as the building blocks of data manipulation in Java. Such types serve only one purpose — containing pure, simple values of a kind.

So why do we want to know the wrapper type?

Attempting to use primitives in any other way and you are in for a lot of hurt.

Cannot make a new instance of a primitive.

Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.newInstance();
//  java.lang.InstantiationException thrown: int
//        at Class.newInstance (Class.java:545) 

Cannot cast to a primitive type.

Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(0);
//  java.lang.ClassCastException thrown: Cannot cast java.lang.Integer to int
//        at Class.cast (Class.java:3578)

Can cast to a null wrapper type. Yeah! \o/

Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(null);

No exceptions and the variable wrapper is of type class java.lang.Integer but with a value of null, a whole lot of good that will do us.

Primitives are not even inherited from wrappers.

boolean isSuperClass = Integer.class.isAssignableFrom(int.class); // false

This is obviously not getting us anywhere so lets rather take a step back from the problem and have a look at the bigger picture.

When at first you don't succeed...

Lets recap: We are retrieving a field which has to come from somewhere so if we were to fill in the gaps left out in the question it might look something like this.

public class Simple {
    public static int field;
    
    public static Field getTheField() {
        return Simple.class.getField("field"); // Actual method that returns our Field
    }

    public static void main(String[] args) {
        Field f = getTheField();
        Class<?> c = f.getType();
    }
}

Instead of fighting against the machine lets rather work with it. One of the perks of primitives are that they will initialise to a default value 0 instead of null. Lets see if we can use that.

Get wrapper class from wrapped instance.

public class Simple {
    public static int field;

    public static Field getTheField() {
        return Simple.class.getField("field"); // Actual method that returns our Field
    }

    public static void main(String[] args) {
        Field f = getTheField();
        Object wrapped = f.get(null);    // Integer value 0
        Class<?> c = wrapped.getClass(); // class java.lang.Integer
    }
}

That was much easier than before and we didn't even have to do anything, auto boxing, everything was done for us. Yet another perk for not trying to go against the stream.

Lets improve on that, refactor and make it a little more reusable by extracting a method.

Implement a manual boxing method.

We can do the same auto boxing with generics:

public class Simple {
    public static int field;

    public static Field getTheField() {
        return Simple.class.getField("field"); // Actual method that returns our Field
    }

    public static <T> T wrap(T t) {
        return t;
    }

    public static void main(String[] args) {
        Field f = getTheField();
        Class<?> c = Simple.wrap(f.get(null)).getClass(); // class java.lang.Integer
    }
}

A simple primitive wrap without ever having to look at the types or use look up tables because java already does it anyway.

Conclusion

The simple solution using pure java to get the wrapper class from a primitive field:

Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.get(null).getClass(); 

Or you can replace null with an instance if the field is not static.

nJoy!

nickl-
  • 8,417
  • 4
  • 42
  • 56
2

(Idea) Get class name and make first letter capital, then call Class.forInstance(className).newInstance(primitive). Exceptions are "char" -> Character and "int" -> Integer

                                Class c=Primitive class object
                                if (c.isPrimitive()) {
                                    if (c == char.class) {
                                        Object wrapper=new Character(primitive var);
                                    }
                                    if (c == int.class) {
                                        Object wrapper=new Integer(primitive var);
                                    }
                                    else {
                                        String name=c.getName();
                                        try {
                                            Class<?> c2=Class.forName("java.lang."+name.substring(0,1).toUpperCase()+name.substring(1,name.length()));
                                            Object wrapper=c2.getConstructor(c).newInstance(primitve_var);
                                        } catch (ClassNotFoundException ex) {
                                            System.out.println("RROR");
                                        }
                                    }

                                }
Luatic
  • 8,513
  • 2
  • 13
  • 34