让我们想象一下,我们必须在运行时根据定义从不同的类调用一种方法。例如,我们收到这样的JSON:
{"calculator": "MyClass1", "parameter1": 1.0, "parameter2": 2.0, ... }
MyClass1和更多类可以扩展某些基类或实现某些接口(只是为了能够在运行时枚举它们)。我们必须创建对象,将参数传递给对象,然后调用calculate()方法。
我可以想到两种方法:
switch(calculatorString){案例“ MyClass1”:计算器= new MyClass1(); ...
使用Java反射
第一种方法确实很愚蠢,因为每次将新的计算器类添加到项目中时都必须更新代码。第二种方法稍好一些,但是IDE无法捕获我们在创建对象和调用方法时发生的任何类型错误。
还有其他方法(可能更好)吗?
答案 0 :(得分:0)
您也许可以使用Java服务提供商接口:
在此处查看示例:
https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html
https://www.baeldung.com/java-spi
它允许您实现不同的实现/服务(在服务文件中仍需要类名),但不必直接使用反射。
您在META-INF
META-INF / services / com.baeldung.rate.spi.ExchangeRateProvider
您的服务可以注册自己,如果允许它们使用输入的json,您将非常灵活。
答案 1 :(得分:0)
反射是在运行时创建对象的最佳方法,但其全部取决于用例。 您还可以将工厂设计模式用于对象创建。
使用ReflectionAPI
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");
}