Java与Scala类型层次结构

Java与Scala类型层次结构,java,scala,types,Java,Scala,Types,目前,我正在学习Scala,我注意到Scala中的类型层次结构更加一致。有Any类型,它实际上是所有类型的超级类型,而JavaObject只是所有引用类型的超级类型 Java示例 Java方法引入了用于原语的包装类,即自动装箱。它还导致了无法使用的类型,例如HashMaps中的键。所有这些都增加了语言的复杂性 Integer i=新的整数(1);//真的需要吗?1已经是int。 HashMap//无效,因为int不是对象子类型。 问题: 将所有类型放在一个层次结构中似乎是个好主意。这就引出了一

目前,我正在学习Scala,我注意到Scala中的类型层次结构更加一致。有Any类型,它实际上是所有类型的超级类型,而JavaObject只是所有引用类型的超级类型

Java示例 Java方法引入了用于原语的包装类,即自动装箱。它还导致了无法使用的类型,例如HashMaps中的键。所有这些都增加了语言的复杂性

Integer i=新的整数(1);//真的需要吗?1已经是int。
HashMap//无效,因为int不是对象子类型。
问题:
将所有类型放在一个层次结构中似乎是个好主意。这就引出了一个问题:为什么Java中没有所有类型的单一层次结构?基本类型和引用类型之间存在划分它有一些优点吗?还是设计决策不好?

这是一个相当广泛的问题

有许多不同的途径可以解释这一点。我将试着说出其中一些

Java关心旧代码;scala基本上没有。 编程语言最终是由他们的社区定义的;一种只有你才能使用的语言是相当有缺陷的,因为你不得不自己写所有的东西。这确实意味着社区做事的方式确实强烈地反映了一种语言是否“好”。java社区强烈倾向于合理的向后兼容性(合理如:如果确实有很好的理由不完全向后兼容,例如因为您正在破坏的功能很少使用,或者几乎总是以有缺陷的方式使用,那没关系),scala社区倾向于从一种时髦的新方式向另一种方式蜂拥而来,任何不在积极开发中的库要么根本不起作用,要么试图将其集成到更现代的scala库中是一项非常令人沮丧的工作

Java不是这样工作的。例如,在泛型中可以观察到这一点:泛型(在
列表
中的T)不在Java1.0中;它们是在java 1.5中引入的,它们的引入方式是所有现有代码都可以继续正常工作,所有库,即使没有更新,也可以与更新的代码一起正常工作,修改现有代码以使用泛型不需要选择新的库或更新,只需要将泛型添加到源文件的正确位置即可

但这是有代价的:擦除。由于1.5版之前的
List
类处理对象,泛型必须作为隐式绑定处理
Object
。Java可以引入
任何
类型,但它基本上是无用的;你不能在很多地方使用它

擦除意味着,在java中,泛型主要是编译器想象出来的:这就是为什么,给定一个列表实例,您不能询问它的组件类型是什么;它根本不知道。您可以编写
列表x=。。。;字符串y=x.get(0)
这很好,但这是因为编译器为您注入了一个不可见的强制转换,并且它知道这个强制转换很好,因为泛型给编译器一个框架来判断这个强制转换永远不会导致ClassCastException(除非显式尝试弄乱它,当您这样做时,编译器总是会发出警告)。但是您不能将对象强制转换为int,这是有充分理由的

Scala社区似乎更愿意接受一种新的代码范例,它与旧的代码范例不进行交互;他们将重构所有代码,并更容易地保留一些旧的库

Java比scala更显式。 Scalac将推断出大量的东西,这或多或少就是语言的设计方式(参见:隐式)。对于某些语言特性,你不得不直接打电话:你在用清晰换取冗长。在您不得不选择的地方,java往往在清晰性方面出错。当我们讨论静默堆和包装器提升时,这一点就特别表现出来了:Java不喜欢这样做。是的,有自动装箱(无声包装),但无声处理
int
,如果处理得当,比包装的变体快几个数量级,对于java来说,整个集合的包装变量只是为了编写
List
,这是一个太远的桥梁:可能很难意识到您正在承受所有性能方面的负面影响

这就是为什么java不会“仅仅”运行:呃,不管怎样,我们将引入一个任意类型的函数,并在运行时通过无声地包装将其全部打包在一起

原语是可执行的。 在java中(scala也在JVM上运行),实际上只有9种类型:int、long、double、short、float、boolean、char、byte和reference。就像在内存中,当你有一个int变量时,它实际上就是这个值,但是如果你有一个字符串变量,这个字符串就存在于堆中的某个地方,你到处传递的值就是指向它的指针。考虑到您不能直接打印指针或对其进行算术运算,在java中,我们希望避免使用这个术语,而是将其称为“引用”,但请不要搞错:这只是一个带有另一个名称的指针

指针本质上是内存浪费和性能降低。这种权衡有很好的理由,但事实就是如此。然而,试图编写既能处理直接值又能处理引用的代码并不容易。通过使编写不可知的代码变得相对困难(这是
Any
类型试图实现的),将这种复杂性转移到您的脸上,是确保程序员永远不会对此感到困惑的一种方法

未来 把以上三点加起来,希望现在可以清楚地看到,
Any
类型要么会带来很多负面影响,要么基本上是无用的(你可以