Java'的好处是什么;什么类型的擦除?

Java'的好处是什么;什么类型的擦除?,java,type-erasure,Java,Type Erasure,我今天读到一篇文章说: 有趣的是,当Java用户抱怨类型擦除时,这是Java唯一做对的事情,而忽略了所有出错的事情 因此,我的问题是: Java的类型擦除有什么好处吗?除了JVM实现对向后兼容性和运行时性能的偏好之外,它(可能)提供了哪些技术或编程风格的好处 一件好事是,当引入泛型时,不需要更改JVM。Java只在编译器级别实现泛型。避免了类似c++的代码膨胀,因为相同的代码用于多种类型;但是,类型擦除需要虚拟分派,而c++代码膨胀方法可以执行非虚拟分派的泛型同一用户在同一对话中的后续帖子: 新

我今天读到一篇文章说:

有趣的是,当Java用户抱怨类型擦除时,这是Java唯一做对的事情,而忽略了所有出错的事情

因此,我的问题是:

Java的类型擦除有什么好处吗?除了JVM实现对向后兼容性和运行时性能的偏好之外,它(可能)提供了哪些技术或编程风格的好处


一件好事是,当引入泛型时,不需要更改JVM。Java只在编译器级别实现泛型。

避免了类似c++的代码膨胀,因为相同的代码用于多种类型;但是,类型擦除需要虚拟分派,而c++代码膨胀方法可以执行非虚拟分派的泛型

同一用户在同一对话中的后续帖子:

新T是一个坏程序。这与“所有命题都是真的”的说法是同构的。我对这一点不感兴趣

(这是对另一位用户声明的回应,即“在某些情况下,‘new T’似乎更好”,其想法是由于类型擦除,
new T()
是不可能的。(这是有争议的-即使
T
在运行时可用,它也可能是一个抽象类或接口,或者它可能是
Void
,或者它可能缺少无参数构造函数,或者它的无参数构造函数可能是私有的(例如,因为它应该是一个单例类),或其无参数构造函数可以指定泛型方法无法捕获或指定的已检查异常-但这是前提。无论如何,如果不进行擦除,您至少可以编写
T.class.newInstance()
,来处理这些问题。))

这种类型与命题同构的观点表明,用户具有形式类型理论的背景。(S)他很可能不喜欢“动态类型”或“运行时类型”,而更喜欢没有downcast和
instanceof
和reflection等的Java。(想想像Standard ML这样的语言,它有着非常丰富的(静态)类型系统,其动态语义不依赖于任何类型信息。)


顺便说一句,值得记住的是,用户是在玩游戏:虽然他可能真心喜欢(静态)类型的语言他并不是真诚地试图说服其他人接受这一观点。相反,原始推文的主要目的是嘲笑那些不同意的人,在一些不同意的人插话后,用户发布了后续推文,如“java具有类型擦除的原因是Wadler等人知道他们在做什么,而不是java用户”.不幸的是,这使得我们很难找出他实际上在思考;但幸运的是,这也可能意味着这样做并不十分重要。对他们的观点有实际深度的人通常不会求助于完全没有内容的巨魔。

类型是一种用于编写程序的构造,它允许编译器检查程序的正确性。类型是值上的命题-编译器验证该命题是否为真

在程序执行过程中,不需要类型信息-这已经由编译器验证。编译器应该可以随意丢弃此信息,以便对代码执行优化-使其运行更快,生成更小的二进制文件等。删除类型参数有助于此

Java通过允许在运行时查询类型信息(反射、instanceof等)来打破静态类型。这允许您构造无法进行静态验证的程序——它们绕过了类型系统。它还错过了静态优化的机会

类型参数被擦除的事实阻止了这些不正确程序的某些实例的构建,但是,如果删除了更多类型信息并删除了设施的反射和实例,则不允许使用更多不正确的程序

擦除对于维护数据类型的“参数性”属性很重要。假设我有一个类型“列表”在组件类型T上参数化,即列表。该类型是一个命题,即该列表类型对任何类型T的作用相同。事实上,T是一个抽象的、无界的类型参数,这意味着我们对该类型一无所知,因此无法对T的特殊情况执行任何特殊操作

e、 假设我有一个列表xs=asList(“3”)。我添加了一个元素:xs.add(“q”)。我以[“3”,“q”)结尾。 因为这是参数化的,所以我可以假设List xs=asList(7);xs.add(8)以[7,8]结尾 我从类型中知道,它对字符串和Int不做一件事

此外,我知道List.add函数不能凭空创造T的值。我知道如果我的asList(“3”)中添加了一个“7”,那么唯一可能的答案将由值“3”和“7”构成。不可能是“2”或“z”被添加到列表中,因为函数将无法构造它。添加这两个值都不合理,并且参数防止构造这些不正确的程序


基本上,擦除可以防止某些违反参数性的方法,从而消除不正确程序的可能性,这是静态类型的目标。

类型擦除之所以是好事,是因为它使不可能的事情是有害的。防止在运行时检查类型参数,有助于理解和推理我们的计划更容易

观察到,我发现有点反直觉的是,当函数签名更通用时,它们变得更容易理解。这是因为可能的实现的数量减少了。考虑一种具有这个签名的方法,我们知道它没有副作用:

public List<Integer> XXX(final List<Integer> l);
公共列表XXX(最终列表l);
有什么可能
public <T> List<T> XXX(final List<T> l);
<A> List<A> flatten(List<List<A>> nestedLists);
flatten(nestedList.map(l -> l.map(any_function)))
    ≡ flatten(nestList).map(any_function)
<T> T broken { return new T(); }
public class GenericClass<T>
{
     private Class<T> targetClass;
     public GenericClass(Class<T> targetClass)
     {
          this.targetClass = targetClass;
     }
     public T newT () { 
         try {
             return targetClass.newInstance(); 
         } catch(/* I forget which exceptions can be thrown here */) { ... }
     }

     private T value;
     /** @throws ClassCastException if object is not a T */
     public void setValueFromObject (Object object) {
         value = targetClass.cast(object);
     }
}
void doStuff(List<Integer> collection) { 
}

void doStuff(List<String> collection) // ERROR: a method cannot have 
                   // overloads which only differ in type parameters
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
public <T> T create(....params, Class<T> classOfT)
{

    ... whatever you do
    ... you will end up
    T = classOfT.newInstance();


    ... or more advanced reflection
    Constructor<T> parameterizedConstructorThatYouKnowAbout = classOfT.getConstructor(...,...);
}