Java 泛型总是提供类型安全性吗?在什么样的最佳用例下

Java 泛型总是提供类型安全性吗?在什么样的最佳用例下,java,performance,generics,type-inference,Java,Performance,Generics,Type Inference,我在Java中使用过很多泛型,并且了解它们的类型擦除功能和类型安全性,但是对于它们在Java中的出现有一些批评 我的问题是使用泛型的最佳优化方案是什么,我不是在说“void printary”之类的东西。是否有任何有利的使用方案或避免它们会起作用。在我看到它们不能提供完整的类型安全性的情况下。 现在考虑下面的代码: // create a vector of strings Vector<String> strings = new Vector<String>(10);

我在Java中使用过很多泛型,并且了解它们的类型擦除功能和类型安全性,但是对于它们在Java中的出现有一些批评

我的问题是使用泛型的最佳优化方案是什么,我不是在说“void printary”之类的东西。是否有任何有利的使用方案或避免它们会起作用。在我看到它们不能提供完整的类型安全性的情况下。

现在考虑下面的代码:

// create a vector of strings
Vector<String> strings = new Vector<String>(10);

// cast it to a vector of objects
Vector<Object> objects = (Vector<Object>)strings;

// insert an object into the vector
objects.add(new Object());
它编译了吗?是的,尽管事实上,它可以强制转换一个字符串数组 对一个对象数组的修改会引入运行时错误的可能性

第8行演示了这一点,导致运行时异常。现在类型擦除应该在第一个示例中起作用,让它编译,然后在数组示例中产生运行时异常,因为cast在编译时使用数组类型字符串[]为数组示例工作这类似于
向量类型向量
,那么泛型在编译时真的有帮助吗?我认为这种行为是强加给开发人员的,因为参数化类型在运行时不存在,因此在第一个示例的第2行中创建的变量只有类型向量

还有什么特别有用的是 java 8?

有一个有趣的例子。它得出的结论是,97.4%的“变量”可以被指定为“使用单一继承的保守命名类型系统的单一静态类型”。如果我们考虑类型系统中的参数多态性(即泛型),这个数字将增加0.5%

这是一个数据点,表明在“真正的程序”中使用泛型类型实际上非常罕见。在许多关于Go编程语言的讨论中可能会发现更多的轶事证据,例如“没有泛型。它有时很糟糕,但很少。”

泛型是一个很好的特性,它允许类型系统捕获程序中稍大的部分。从用户体验的角度来看,它也很好,因为它节省了输入(用手指),IDE可以提供自动完成功能(与在Java1.4中对对象进行手动类型转换相比)。但是泛型并不经常出现,并且可以很容易地被代码生成所取代,因此在我看来,泛型在软件开发中几乎不重要

(事实上,Go在这里是作弊。它们确实有泛型类型,但仅适用于5个左右的内置数据结构(映射、通道等)。用户不能定义自己的泛型类型,在指定函数参数时也不能使用泛型类型通配符。显然,这足以满足演示文稿的作者。)有一个有趣的故事。它得出的结论是,97.4%的“变量”可以被指定为“使用单一继承的保守命名类型系统的单一静态类型”。如果我们考虑类型系统中的参数多态性(即泛型),这个数字将增加0.5%

这是一个数据点,表明在“真正的程序”中使用泛型类型实际上非常罕见。在许多关于Go编程语言的讨论中可能会发现更多的轶事证据,例如“没有泛型。它有时很糟糕,但很少。”

泛型是一个很好的特性,它允许类型系统捕获程序中稍大的部分。从用户体验的角度来看,它也很好,因为它节省了输入(用手指),IDE可以提供自动完成功能(与在Java1.4中对对象进行手动类型转换相比)。但是泛型并不经常出现,并且可以很容易地被代码生成所取代,因此在我看来,泛型在软件开发中几乎不重要


(事实上,Go在这里是作弊。它们确实有泛型类型,但仅适用于5个左右的内置数据结构(映射、通道等)。用户不能定义自己的泛型类型,在指定函数参数时也不能使用泛型类型通配符。显然,这足以满足演示文稿的作者。)

由于类型擦除,泛型类型信息在运行时丢失。 因此,编译器会确保您的第一个示例不会编译,否则会导致运行时异常

数组是协变的,这使得代码可以编译

class A {}
class B extends A {}
class C extends A {}

A a = new B();
A[] as = new B[0];
as[0] = new C(); // runtime error, as is an array of Bs at runtime
但是java中的数组有一个可修改的类型,即对于数组,数组类型在运行时是已知的,因此对错误元素类型的赋值会导致运行时出现
ArrayStoreException
。tl;dr数组在java中被破坏


阅读此内容以了解更多信息:

由于类型擦除,泛型类型信息在运行时丢失。 因此,编译器会确保您的第一个示例不会编译,否则会导致运行时异常

数组是协变的,这使得代码可以编译

class A {}
class B extends A {}
class C extends A {}

A a = new B();
A[] as = new B[0];
as[0] = new C(); // runtime error, as is an array of Bs at runtime
但是java中的数组有一个可修改的类型,即对于数组,数组类型在运行时是已知的,因此对错误元素类型的赋值会导致运行时出现
ArrayStoreException
。tl;dr数组在java中被破坏


阅读本文了解更多信息:

泛型与代码的性能无关,而是帮助您以一种不会在运行时引发意外的
ClassCastException
的方式实现代码。既然您已经知道什么是类型擦除,而且在运行时(几乎)没有泛型信息,为什么您认为泛型会影响运行时性能?目标类型推断特别有助于消除对冗余类型注释的需要,从而降低代码的噪音。@KonstantinYovkov,我并不是先说运行时性能,你能告诉我上面的代码会产生什么结果吗是非法的类型转换。你的代码甚至都不会编译,更不用说毫无例外地运行了