为什么包装类没有通用的超类型?



java包装类(java.lang.Integerjava.lang.Boolean,...)没有公共超类型背后是否有特殊原因?


我问是因为(例如)沿着经典Object::getClassWrapperType::getType函数会非常方便,这将返回基元类型的类。

更具体地说,上下文通过反射调用构造函数,其中您只有Class<T>和参数Object[]

例如:

public static <T> T createInstance(Class<T> clz, Object... params) throws Exception

为了获取构造函数,我可以通过以下方式获取参数类型:

Class<?>[] c = Arrays
.stream(params)
.map(Object::getClass)
.toArray(Class<?>[]::new);
return clz.getConstructor(c).newInstance(params);

但这当然会失败,像String::new(char[], int, int);这样的构造函数

如果该超类型存在,我可以执行以下操作:

.map( o -> o.getClass().isPrimitive() ? ((WrapperType) o).getType() : o.getClass() )

我想开发人员没有实现它有一个特殊的原因java

Java 设计人员在决策中可能不太抽象,并且找不到数字类型之间的许多相似之处(例如Integer) 和非数字类型(例如Boolean) 按超类对它们进行分组。

虽然,所有数值类型都扩展Number真正表示"可转换为基元类型的数值bytedoublefloatintlongshort"。

实际上,所有包装类都有一个通用的接口Comparable<T>(例如Comparable<Integer>Integer)。

我可以看到这将是多么实用,但就抽象而言,这将是一个大混乱。假设你有包装器Integer和Double以及该家族中的其他包装器,它们确实有java.lang.Number作为他们的超级。然而,它们与布尔值之间没有语义关系(将c的影响分开)。

但是为了论证起见,让我们考虑一下它们都在一个大桶里并且是包装器,它们仍然是数字吗?

考虑到语言历史上对多重继承的厌恶,如果你要选择的话,拥有数字会有更多的场景。

在 SE 8 的语言功能发生重大革命性变化之后,我们现在能够通过接口进行多重继承,同时在这种情况下使用标准实现。如果进一步分析,他们将在逻辑推理中得出结论,这些案件需要合同而不是继承;因此,即使这样做了,这也是接口的工作。

考虑到实现这一点的可靠方法是相当新的,并且 Wrappers 将是一种过于通用的方式,我们可以看到最好不要拥有它。虽然现在有可能,但有历史和语义上的原因可以解释为什么它没有出现,至少作为一个超级类。抽象是这里的关键。但是没有什么能阻止你在管道中插入工厂,或实现提到的接口。

臀部线,关键因素有:

  1. 抽象:这更像是一个契约或 is-a 关系
  2. 历史:泛型和通过接口的多重继承
  3. 想象一下,如果我们愿意容纳,继承三的大小 情况如下:它首先是一个包装器,然后是一个数字或布尔值。

最新更新