为什么包装类没有常见的超类型?

时间:2018-04-26 13:26:19

标签: java primitive-types

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

我问,因为在经典WrapperType::getType上有(例如)Object::getClass函数会返回原始类型的类是非常方便的。

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

E.g:

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开发人员没有实现它。

2 个答案:

答案 0 :(得分:1)

Java设计人员的决策可能不是太抽象,并且在数字类型(例如Integer)和非数字类型(例如Boolean)之间找不到很多相似之处超类。

但是,所有数字类型都扩展Number,它真正代表“可转换为基本类型bytedoublefloat,{{1}的数值},intlong“。

实际上,所有包装类都有一个共同的接口short(例如Comparable<T>的{​​{1}}。)

答案 1 :(得分:1)

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

但是出于争论的缘故,让我们认为他们都在一个大桶里并且是Wrappers,他们还是数字吗?

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

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

考虑到实现这一点的可靠方法是相当新的,并且Wrappers将是一种过于普遍的方式来实现它,我们可以看到最好不要拥有它。尽管现在已经成为可能,但是至少作为一个超级阶级,有一些历史和语义原因可以解释为什么它不是主持人。抽象是关键。但是没有什么可以阻止你在你的管道中插入工厂,或者实现上面提到的接口。

Buttom line,关键因素是:

  1. 抽象:这更像是合同或是一种关系
  2. 历史:泛型,以及通过接口的多重继承
  3. 如果我们愿意的话,想象一下继承的大小 例如:首先是包装器,然后是数字或布尔值..