简体   繁体   中英

java access Integer constructor through reflection

I'm having this code. Why doesn't it works?(Working meaning that it display 3) How can I fix it?

public class Main {
    public static<V> V copy(V var){
        try{ 
            return (V) var.getClass().getConstructor(var.getClass()).newInstance(var);
        }
        catch(Exception e){
            System.out.println("Copy faield " + e.getMessage() + " ");
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        Integer a = new Integer(3);
        Integer b = copy(a);

        System.out.println(a);
        System.out.println(b);


    }
}

This is the output:

 Copy faield java.lang.Integer.<init>(java.lang.Integer) 
    java.lang.NoSuchMethodException: java.lang.Integer.<init>(java.lang.Integer)
        at java.lang.Class.getConstructor0(Class.java:2818)
        at java.lang.Class.getConstructor(Class.java:1723)
        at Main.copy(Main.java:7)
        at Main.main(Main.java:19)
    3
    null

Thanks!

The problem here is the distinction between:

Integer.class
int.class

The constructor for Integer takes an int parameter, not an Integer .

To get your magic method to work, you would need to do a special check of the type, and if it's a wrapper class, actually look for a constructor whose parameter is the corresponding primative type.

AFAIK there's no built in way to get the primatove class from the wrapper class - you could use a map and populate it with the mappings:

private static final Map<Class<?>, Class<?>> MAP = new HashMap<>() {{
    put(Integer.class, int.class);
    put(Long.class, long.class);
    // etc
}};

Then in your method:

Class<?> type = MAP.containsKey(var.getClass()) ? MAP.get(var.getClass()) : var.getClass();
return (V) var.getClass().getConstructor(type).newInstance(var);

It's OK to pass the int as an Integer in the parameter value - that at least gets auto unboxed.

Generic approach of copying any object to another object. This util class is available in the package - org.apache.commons.lang3.

 Integer c = (Integer) SerializationUtils.clone(a);

To really understand why "new Integer(new Integer(5))" works while reflections doesn't it's useful to look at the generated byte code for the first case:

ICONST_5
INVOKESPECIAL java/lang/Integer.<init> (I)V
INVOKEVIRTUAL java/lang/Integer.intValue ()I
INVOKESPECIAL java/lang/Integer.<init> (I)V

... as you can see, a call is being made to the intValue() method of Integer "under the hood". So, the java compiler is actually translating your "new Integer(new Integer(5))" to "new Integer(new Integer(5).intValue())". This means it can use the constructor which takes an int.

Because the java compiler cannot know the actual runtime type of the variable for the reflections call it cannot do anything similar and can only look for a constructor with the actual runtime type argument.

int是一个类型,但Integer是一个包装器(类),它使用int作为具有许多功能的对象

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM