Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在没有可变类型的情况下,是否存在不变类型参数的情况?_Java_Generics_Types_Immutability_Covariance - Fatal编程技术网

Java 在没有可变类型的情况下,是否存在不变类型参数的情况?

Java 在没有可变类型的情况下,是否存在不变类型参数的情况?,java,generics,types,immutability,covariance,Java,Generics,Types,Immutability,Covariance,Java数组不是完全类型安全的,因为它们是协变的:ArrayStoreException可能发生在别名数组上。另一方面,Java集合的类型参数是不变的:例如,List不是List的子类型(这可能有点违反直觉)。 动机似乎与Lists和其他可变集合有关,因此为了保持类型系统正常,它们的类型参数必须是不变的 如果一种编程语言只支持不可变类型,那么类型参数是协变或逆变(但从不不变)的类型系统能工作吗?换句话说,要使用Scala表示方差的方法,可以使用列表[+E],函数[-T,+R],映射[+K,+V]

Java数组不是完全类型安全的,因为它们是协变的:
ArrayStoreException
可能发生在别名数组上。另一方面,Java集合的类型参数是不变的:例如,
List
不是
List
的子类型(这可能有点违反直觉)。 动机似乎与
List
s和其他可变集合有关,因此为了保持类型系统正常,它们的类型参数必须是不变的

如果一种编程语言只支持不可变类型,那么类型参数是协变或逆变(但从不不变)的类型系统能工作吗?换句话说,要使用Scala表示方差的方法,可以使用
列表[+E]
函数[-T,+R]
映射[+K,+V]
,等等。 我知道有些较旧的语言(例如)似乎只支持co-/逆变参数类型而不受影响


我的一般问题是:在一个完全不可变的数据类型的世界中,有没有一种情况会特别需要一个不变的参数类型(与共变或逆变相反)?是否有一些不可变的数据结构的例子,只有使用不变的类型参数才是正确的?

因此,每种类型的系统要么允许一些不健全的程序,要么禁止一些健全的程序,要么两者兼而有之(这是,你提出的任何限制都必然会排除一些本来可以被允许的声音节目。另一方面,人类是无限聪明的,所以从另一个意义上说,答案是否定的:如果你像你描述的那样加上一个限制,没关系,人们会在需要的时候找到解决的办法。(当然,有时他们会想出一个你不喜欢的解决办法,比如放弃你的语言。)

但我认为你真正想要的是一个令人信服的例子:一个现实的例子,在这个例子中,你可以选择直接支持这个例子,也可以坚持你的建议,要求所有类型参数要么是协变的,要么是逆变的,你的直觉会告诉你放弃这个提议,这样你就可以直接支持这个例子


由于您已经确定了类型参数不能协变的各种情况,以及类型参数不能逆变的各种情况(例如,函数[-t,+R]可以,但反过来会完全不可靠),因此一个好方法是搜索两次使用同一类型参数的情况,一次是不能协变的,一次是不能逆变的。一个简单的例子是UnaryOperator[T],我很惊讶您编写了
Map[-K,+V]
;当然应该是
映射[+K,+V]
?(不能在不中断迭代的情况下允许
-K
。但是
+K
可以,因为缺少的键会隐式映射为null。)唯一有争议的部分是第一句半。如果你抛开Java列表的东西,一般的问题是有趣的,没有偏见的。Re:“[我的假设]之一是没有空指针,所以我想到的这个虚构的Map版本会返回一个可选的或并集或和类型,比如'V | Nothing'”:好的,但这与此目的是一样的。Re:“映射基本上是一个用于获取键值的函数,这就是为什么我对映射使用了与函数相同的类型参数方差”:映射有点像一个局部函数,因为它的键集是其键类型实例集的子集。它通过将缺少的键映射到默认值来补偿这一点,[continued][continued],这意味着允许检查键类型错误的映射。Re:“根本不会有迭代器这样的东西,因为它依赖于可变的内部状态”:我认为迭代是集合的一个基本特性;幸运的是,您可以使用不可变迭代器(例如,使用
head
tail
方法,后者返回新的迭代器)。
List
不是
List
的子类型与可变性无关,虽然问题只表现为可变结构,但不可变结构是一种边缘情况。乍一看和没有任何想法,它不是一个亚类型似乎是违反直觉的,但当你考虑的含义是一个子类型,意味着你可以指定一个子类型的变量的超类型,它应该是显而易见的,为什么它不是。谢谢,@鲁克,非常全面的答案!特别是您描述的
UnaryOperator[T]
/
函数[T,T]
示例以及
比较器[K]
和'floorrentry
/
ceilingEntry'方法的问题正是我要寻找的反例!