首页 > 解决方案 > 在 Java 中运行时调用不同类的最佳方法

问题描述

假设我们必须在运行时根据定义从不同的类中调用一个方法。例如,我们收到这样的 JSON:

{"calculator": "MyClass1", "parameter1": 1.0, "parameter2": 2.0, ... }

MyClass1 和更多类要么扩展一些基类,要么实现一些接口(只是为了能够在运行时枚举它们)。我们必须创建对象,将参数传递给对象并调用 calculate() 方法。

我可以想到两种方法来做到这一点:

  1. switch(calculatorString) { case "MyClass1":calculator = new MyClass1(); ...

  2. 使用 Java 反射

第一种方法非常愚蠢,因为每次将新的计算器类添加到项目中时都必须更新代码。第二种方法稍好一些,但 IDE 无法捕获我们在创建对象和调用方法时犯的任何类型错误。

还有其他方法可以做到这一点(可能更好)?

标签: javajsonreflectionruntime

解决方案


反射是在运行时创建对象的最佳方式,但它完全取决于用例。您还可以使用工厂设计模式进行对象创建。

使用反射API

try {
            cls = Class.forName(className);
            instance = cls.newInstance();
            instance = BeanUtils.populateBean(properties, cls);
} catch (Exception e) {
     e.printStackTrace();           
}

BeanUtil 类

public static Object populateBean(Map<String, Object> propertyMap, Class<?> clazz) throws Exception {
    PropertyUtilsBean bean = new PropertyUtilsBean();
    Object obj = null;
    try {
        obj = clazz.newInstance();

        for(Map.Entry<String, Object> entrySet: propertyMap.entrySet()) {
            PropertyDescriptor descriptor = null;
            try {
                descriptor =
                        bean.getPropertyDescriptor(obj, entrySet.getKey());

                if (descriptor == null) {
                    continue;
                }
                Method writeMethod = bean.getWriteMethod(descriptor);
                writeMethod.invoke(obj, convert(descriptor.getPropertyType(), entrySet.getValue(), DATE_PATTERN));

            } catch (IncompatibleConversion e) {
                throw e;
            } catch (Exception e) {
                throw new Exception("Unable to parse");
            }
        }

    }catch(Exception e) {
        throw e;
    }

    return obj;
}

转换类

private static Object convert(Class<?> clzz, Object value, String datePattern) throws Exception {

    if (clzz.isAssignableFrom(BigInteger.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof BigInteger) {
            return value;
        }

        try {
            return new BigInteger(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(BigDecimal.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof BigDecimal) {
            return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
        }

        try {
            return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Integer.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Integer) {
            return value;
        }

        try {
            return new Integer(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Long.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Long) {
            return value;
        }

        try {
            return new Long(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(String.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof String) {
            return value;
        }

        try {
            return value.toString();
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Date.class)) {

        if (value == null) {
            return value;
        }

        if (value instanceof Date) {
            return value;
        }

        if (datePattern == null) {
            throw new Exception("date pattern cannot be null");
        }
        try {

            SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
            return sdf.parse(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Byte.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Byte) {
            return (value);
        } else if (value instanceof Number) {
            return new Byte(((Number) value).byteValue());
        }

        try {
            return (new Byte(value.toString()));
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Float.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Float) {
            return (value);
        }

        try {
            return new Float(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Double.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Double) {
            return (value);
        }

        try {
            return new Double(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    }

    throw new Exception("Incompactible Conversion");
}

推荐阅读