值得一提的是,大多数脚本语言(如 Perl)和非静态编译时语言(如 Pick)支持自动运行时动态字符串到(相对任意)对象的转换。这也可以在 Java 中实现,而不会失去类型安全性,并且静态类型语言提供的好东西不会像其他一些通过动态转换做坏事的语言那样产生令人讨厌的副作用。一个做一些有问题的数学的 Perl 例子:
print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
在 Java 中,这可以通过使用我称为“交叉转换”的方法更好地完成(恕我直言)。通过交叉转换,反射用于构造函数和方法的延迟加载缓存,这些构造函数和方法通过以下静态方法动态发现:
Object fromString (String value, Class targetClass)
不幸的是,没有内置的 Java 方法(例如 Class.cast() )可以对 String 到 BigDecimal 或 String 到 Integer 或任何其他没有支持类层次结构的转换执行此操作。就我而言,重点是提供一种完全动态的方式来实现这一点——我认为先前的参考不是正确的方法——必须对每次转换进行编码。简而言之,如果合法/可能,实现只是从字符串转换。
所以解决方案是简单的反射寻找公共成员:
STRING_CLASS_ARRAY = (new Class[] {String.class});
a) 成员成员 = targetClass.getMethod(method.getName(),STRING_CLASS_ARRAY); b) 成员成员 = targetClass.getConstructor(STRING_CLASS_ARRAY);
您会发现所有原语(Integer、Long 等)和所有基础知识(BigInteger、BigDecimal 等)甚至 java.regex.Pattern 都通过这种方法涵盖。我在需要进行更严格检查的大量任意字符串值输入的生产项目中使用它并取得了重大成功。在这种方法中,如果没有方法或调用该方法时抛出异常(因为它是非法值,例如 BigDecimal 的非数字输入或模式的非法 RegEx),则提供特定于目标类的内在逻辑。
这样做有一些缺点:
1)你需要很好地理解反射(这有点复杂,不适合新手)。2) 一些 Java 类和确实 3rd-party 库(令人惊讶)没有正确编码。也就是说,有些方法将单个字符串参数作为输入并返回目标类的实例,但这不是您所想的......考虑一下 Integer 类:
static Integer getInteger(String nm)
Determines the integer value of the system property with the specified name.
上述方法实际上与 Integers 作为包装基元 int 的对象无关。Reflection 会发现这可能是错误地从字符串创建整数的候选对象,而不是解码、valueof 和构造函数成员 - 它们都适用于大多数任意字符串转换,您实际上无法控制输入数据但只想知道是否可能是整数。
为了解决上述问题,寻找抛出异常的方法是一个好的开始,因为创建此类对象实例的无效输入值应该抛出异常。不幸的是,对于异常是否被声明为已检查,实现会有所不同。例如,Integer.valueOf(String) 会抛出一个检查过的 NumberFormatException,但在反射查找期间找不到 Pattern.compile() 异常。同样,我认为这种动态“交叉转换”方法的失败并不是对象创建方法中异常声明的非常非标准的实现。
如果有人想了解有关上述实现方式的更多详细信息,请告诉我,但我认为该解决方案更加灵活/可扩展,并且代码更少,而不会丢失类型安全的优点。当然,“了解你的数据”总是最好的,但正如我们许多人所发现的那样,我们有时只是非托管内容的接收者,必须尽我们所能正确使用它。
干杯。