关于Java中的通用数组创建 [英] about generic array creation in Java

查看:109
本文介绍了关于Java中的通用数组创建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  List< String> [] stringLists = new List [1]; 

这行可以在我的AndroidStudio IDE上通过编译,但有警告。它似乎违反了面向对象语言的基本规则:超类对象可以使用子类实例实例化,但反过来不是。

  String [] ss = new Object [1]; //不会编译

我们知道List是任何通用List类型的超类型,例如在这种情况下,列出< String> 。因为数组是协变的,所以我认为List []类型是超级的 List< String> [] 类型。为什么 List< String> [] 可以用 List []

$ b $实例化b

解决方案

我认为 JLS,§4.8,原始类型回答了您的为什么作业有效的实际问题:


只允许使用原始类型作为遗留代码兼容性的让步。强烈建议在将泛型引入Java编程语言之后编写的代码中使用原始类型。未来版本的Java编程语言可能会禁止使用原始类型。


它可以与预先仿制代码。一般来说,如果你打算进行类型安全的话,你不应该使用参数化类型的数组,如果作者写道:如果你写了:

 列表与LT;列表与LT;字符串>> lists = new ArrayList<>(); 






您对违反类型安全规则的假设是错误的。你的意思是 List 不是 List< String> 的子类型。但是,在Java类型系统中,问题的答案是: List List的子类型< String> ?既不是是,也不是否。这是这个问题不能回答。



(这也可能是不正确的混淆类型和类。只有一个 List class,但 List< String> List< Object> 不同的类型奖金: List< String> 不是 List< Object>的子类型




为了增加更多关于发生的细节,JLS解释了什么是转换允许在§5.2中的变量赋值中, 分配上下文。值得注意的是,该列表以下列结尾:


如果在应用了上面列出的转换之后,结果类型是原始类型(§4.8),未经检查的转换(§5.1.9< a>)可能会被应用。


后者链接至§5.1.9,Unchecked Conversions,一些形式化的解释什么是未经检查的转换是,重申理由(强调我的):
$ b


未经检查的转换用于实现遗留代码的平稳互操作,在引入泛型类型之前编写,使用经过转换的库使用泛型(我们称之为generificatio的过程N)。在这种情况下(最显着的是,Collection框架的客户端在 java.util 中),遗留代码使用原始类型(例如 Collection 而不是集合< String> )。原始类型表达式作为参数传递给库方法,这些方法使用这些相同类型的参数化版本作为相应形式参数的类型。



这种调用不能是在使用泛型的类型系统下显示为静态安全。拒绝此类调用会使大型现有代码无效,并阻止它们使用较新版本的库。这反过来会阻止图书馆供应商利用通用性。为了防止这种不受欢迎的事件发生,可以将原始类型转换为对原始类型引用的泛型类型声明的任意调用。 虽然转换不健全,但可以容忍作为实用性的让步。在这种情况下会发出未经检查的警告。

官方的故事的确是从原始类型到参数化类型的未检查转换被故意添加到语言中,尽管可能不安全,并且出于兼容性原因仅标记有编译警告。 (Java非常努力确保在版本X中编译的代码永远不会编译失败,或者在版本X + 1中不再有用。)


just found a line of code that I do not quite understand.

List<String>[] stringLists = new List[1];

This line can pass the compilation on my AndroidStudio IDE though with warning. It seems to violate the basic rule of Object Oriented language: "the super class object can be instantiated with child class instance, but not vice versa."

String[] ss = new Object[1];  // won't compile

We know that List is super type of any generic List types, such as List<String> in this case. And as array is covariant, so I think List[] type is super of List<String>[] type. Why a List<String>[] can be instantiated with a List[]?

解决方案

I think the JLS, §4.8, "Raw Types" answers your actual question of why the assignment is valid:

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

It's for compatibility with pre-generics code. Generally if you're going for type-safety, you shouldn't use arrays of parameterised types at all, it would've been better if the author wrote:

List<List<String>> lists = new ArrayList<>();


Your assumption about a rule of type safety being violated is mistaken. You're saying that List is not a subtype of List<String>. However, in the Java type system, the answer to the question: "Is List a subtype of List<String>?" is neither "Yes", nor is it "No." It's "this question cannot be answered."

(It's also probably not correct to conflate "types" and "classes." There is only one List class, but List<String> and List<Object> are different types. Bonus: List<String> is not a subtype of List<Object>.)


To add a bit more detail about what's going on, the JLS explains what conversions are allowed in a variable assignment in §5.2, "Assignment Contexts". Notably, the list ends with:

If, after the conversions listed above have been applied, the resulting type is a raw type (§4.8), an unchecked conversion (§5.1.9) may then be applied.

The latter link to §5.1.9, "Unchecked Conversions", after some formalisms explaining what an unchecked conversion is, reiterates the rationale (emphasis mine):

Unchecked conversion is used to enable a smooth interoperation of legacy code, written before the introduction of generic types, with libraries that have undergone a conversion to use genericity (a process we call generification). In such circumstances (most notably, clients of the Collections Framework in java.util), legacy code uses raw types (e.g. Collection instead of Collection<String>). Expressions of raw types are passed as arguments to library methods that use parameterized versions of those same types as the types of their corresponding formal parameters.

Such calls cannot be shown to be statically safe under the type system using generics. Rejecting such calls would invalidate large bodies of existing code, and prevent them from using newer versions of the libraries. This in turn, would discourage library vendors from taking advantage of genericity. To prevent such an unwelcome turn of events, a raw type may be converted to an arbitrary invocation of the generic type declaration to which the raw type refers. While the conversion is unsound, it is tolerated as a concession to practicality. An unchecked warning is issued in such cases.

The official story is indeed that unchecked conversions from raw type to parameterised type were added to the language deliberately, despite being potentially unsafe, and are only marked with a compilation warning for compatibility reasons. (Java very much tries to ensure that code that compiled in version X never fails to compile or ceases to be useful in version X+1.)

这篇关于关于Java中的通用数组创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆