实例化一个未知的Object,其构造函数将一个基本数组作为参数(反射)

时间:2017-07-23 01:42:25

标签: java arrays generics reflection

该程序通过递归迭代构造函数的参数来随机实例化任何Object,直到找到可以随机化的基元或包装参数。但是,当构造函数将基本数组作为参数时,我得到一个

java.lang.IllegalArgumentException: argument type mismatch

我已经通过Stack Overflow和互联网,但似乎无法找到如何将包装器数组提供给构造函数或将包装器数组转换为基本数组。

我已经考虑了以下修复方法,但我不确定如何实现它们:

  1. 创建java.lang.reflect.Constructor的自定义子类并更改getParameterTypes()方法,以便在给定参数时使用 是一个原始数组(例如int[]),将其更改为Integer[]。我认为这可能会产生一些不利影响。
    1. 弄清楚如何迭代地将项目“添加”到varargs / Object[] parameterValues,以便在遇到它时检查每个parameterValues[i],看看它是否是一个包装数组,然后将其更改为原始数组。这就产生了一个问题,即原始数组(例如byte[])无法进入构造函数.newInstance(parameterValues)的parameterValues
  2. 如果您愿意,可以阅读所有代码,但这两个代码并不特别相关。大部分操作和我的问题出现在nextRandom(Class<?> cls)中,其中一些出现在randomBase(BASE_TYPE baseType)中。

    代码:

    import java.lang.reflect.*;
    import java.util.Random;
    
    /**
     * Sources used:
     * https://stackoverflow.com/questions/709961/determining-if-an-
       object-is-of-primitive-type
     * https://stackoverflow.com/questions/4936819/java-check-if-enum-
       contains-a-given-string
     * https://stackoverflow.com/questions/10189016/generate-short-
       random-number-in-java
     *
     * Created by Ward Bradt/ BlueOxile on July 22, 2017
     * https://github.com/wardbradt
     */ 
    public class RandomGenerator {
    
        public enum BASE_TYPE {
            INTEGER (int.class, Integer.class),
            DOUBLE (double.class, Double.class),
            FLOAT (float.class, Float.class),
            LONG (long.class, Long.class),
            SHORT (short.class, Short.class),
            BYTE (byte.class, Byte.class),
            BOOLEAN (boolean.class, Boolean.class),
            CHAR (char.class, Character.class);
    
            private final Class<?> primitiveClass;
            private final Class<?> wrapperClass;
    
            BASE_TYPE(Class<?> primitive, Class<?> wrapper) {
                this.primitiveClass = primitive;
                this.wrapperClass = wrapper;
            }
    
            public Class<?> getPrimitiveClass() {
                return primitiveClass;
            }
    
            public Class<?> getWrapperClass() {
                return wrapperClass;
            }
        }
    
        public enum BASE_TYPE_ARRAY {
            INTEGER (int[].class, Integer[].class, BASE_TYPE.INTEGER),
            DOUBLE (double[].class, Double[].class, BASE_TYPE.DOUBLE),
            FLOAT (float[].class, Float[].class, BASE_TYPE.FLOAT),
            LONG (long[].class, Long[].class, BASE_TYPE.LONG),
            SHORT (short[].class, Short[].class, BASE_TYPE.SHORT),
            BYTE (byte[].class, Byte[].class, BASE_TYPE.BYTE),
            BOOLEAN (boolean[].class, Boolean[].class, BASE_TYPE.BOOLEAN),
            CHAR (char[].class, Character[].class, BASE_TYPE.CHAR);
    
            private final Class<?> primitiveArrayClass;
            private final Class<?> wrapperArrayClass;
            private final BASE_TYPE baseType;
    
            BASE_TYPE_ARRAY(Class<?> primitiveArray, Class<?> wrapperArray, BASE_TYPE b) {
                this.primitiveArrayClass = primitiveArray;
                this.wrapperArrayClass = wrapperArray;
                this.baseType = b;
            }
    
            public Class<?> getPrimitiveClass() {
                return baseType.getPrimitiveClass();
            }
    
            public Class<?> getPrimitiveArrayClass() {
                return primitiveArrayClass;
            }
    
            public Class<?> getWrapperClass() {
                return baseType.getWrapperClass();
            }
    
            public Class<?> getWrapperArrayClass() {
                return wrapperArrayClass;
            }
    
            public BASE_TYPE getBaseType() {
                return baseType;
            }
        }
    
        public static Object nextRandom(Class<?> cls) throws IllegalAccessException, InvocationTargetException, InstantiationException {
            // base case: primitive array or wrapper array
            if (cls.isArray()) {
                for (BASE_TYPE_ARRAY i : BASE_TYPE_ARRAY.values()) {
                    if (cls.equals(i.getPrimitiveArrayClass()) || cls.equals(i.getWrapperArrayClass())) {
                        // later: random wrapper of cls if primitive
                        // later: is slightly inefficient because we iterate over BTA.values() than iterate in
                        // randomBase using a switch statement.
                        return randomBaseArray(i);
                    }
                }
            }
            // base case: if primitive or wrapper
            else {
                for (BASE_TYPE i : BASE_TYPE.values()) {
                    if (cls.equals(i.getPrimitiveClass()) || cls.equals(i.getWrapperClass())) {
                        // later: random wrapper array of cls
                        return randomBase(i);
                    }
                }
            }
    
            Constructor<?> constructor = cls.getConstructors()[0];
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            Object[] parameterValues = new Object[parameterTypes.length];
    
            for (int i = 0; i < parameterValues.length; i++) {
                // Recursively creates objects/ parameters for constructor
                parameterValues[i] = nextRandom(parameterTypes[i]);
            }
    
            // ----------------------
            // EXCEPTION THROWN HERE
            // ----------------------
            return constructor.newInstance(parameterValues);
        }
    
        public static Object randomBase(BASE_TYPE baseType) {
            Random rand = new Random();
            switch (baseType) {
                case BYTE:
                    return randomByte();
                case CHAR:
                    return randomChar();
                case LONG:
                    return rand.nextLong();
                case FLOAT:
                    return rand.nextFloat();
                case DOUBLE:
                    return rand.nextDouble();
                case SHORT:
                    return randomShort();
                case BOOLEAN:
                    return rand.nextBoolean();
                case INTEGER:
                    return rand.nextInt();
            }
            throw new IllegalArgumentException();
        }
    
        public static Object[] randomBaseArray(BASE_TYPE_ARRAY baseTypeArray) {
            short srt = (short) (1 + new Random().nextInt(Short.MAX_VALUE));
            Object arr = Array.newInstance(baseTypeArray.getWrapperClass(), srt);
    
            for (int i = 0; i < Array.getLength(arr); i++) {
                Array.set(arr, i, randomBase(baseTypeArray.getBaseType()));
            }
            return (Object[])arr;
        }
    
        public static Byte randomByte() {
            byte[] b = new byte[1];
            new Random().nextBytes(b);
            return b[0];
        }
    
        public static Character randomChar() {
            return (char)(new Random().nextInt(85) + 32);
        }
    
        public static Short randomShort() {
            return (short) (Short.MIN_VALUE + new Random().nextInt(Short.MAX_VALUE * 2 + 2));
        }
    
        public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
            // I don't fully know how to use @SuppressWarnings yet, so most of my methods throw these exceptions^
            String str = (String)nextRandom(String.class);
        }
    }
    

0 个答案:

没有答案