Simple way to get wrapper class type in Java

前端 未结 9 1436
天命终不由人
天命终不由人 2020-11-29 09:14

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 w

相关标签:
9条回答
  • 2020-11-29 09:39

    (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");
                                            }
                                        }
    
                                    }
    
    0 讨论(0)
  • 2020-11-29 09:42

    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.

    0 讨论(0)
  • 2020-11-29 09:46

    There's also com.sun.beans.finder.PrimitiveWrapperMap#getType(primitiveName). But of course using classes from the "com.sun" package is not really recommended...

    0 讨论(0)
  • 2020-11-29 09:47

    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.

    0 讨论(0)
  • 2020-11-29 09:47

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

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

    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.

    Attempting to use them 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 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 since java.lang.reflect.Field is marked final and exposes no public constructors.

    If we were to fill in the gaps it might look something like this.

    public class Simple {
        public static int field;
    
        public static void main(String[] args) {
            Field f = Simple.class.getField("field"); // Actual method that returns my Field
            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 void main(String[] args) {
            Simple boxer = new Simple();
            Field f = Simple.class.getField("field");
            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, 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.

    public class Simple {
        public static int field;
    
        public static <T> T wrap(T t) {
            return t;
        }
    
        public static void main(String[] args) {
            Field f = Simple.class.getField("field");
            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.

    The simple solution

    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!

    0 讨论(0)
  • 2020-11-29 09:47

    With a more recent jdk, this is a one-liner now:

    @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.

    0 讨论(0)
提交回复
热议问题