Answers:
好吧,动机(向后兼容)既是优点也是缺点。这是不利的,因为我们所有人都希望拥有可更改的类型,但是要付出的代价很高。考虑C#中的设计选择。它们具有可更改的类型,但是现在它们具有重复的API。因此,想象一下一个Java API,其中每个参数化类都有相同的API。现在,想象一下自己将数千行代码从旧类移植到新的通用类。现在,谁不认为重复的API是不利的呢?但是,嘿,它们有可更改的类型!
因此,主要动机是“进化,而不是革命”。从逻辑上讲,每个决策都需要权衡。
除了上面提到的其他缺点外,我们还可以添加这样一个事实,即在编译时很难对类型擦除进行推理,因为尚不清楚某些类型会被删除,这会导致非常奇怪且难以发现错误。
的存在桥的方法(此语法编译器生成的方法,以保持二进制兼容性)也被看作是不利的。这些恰恰是我在上一段中提到的错误的原因之一。
主要缺点来自于一个显而易见的事实,即泛型类型只有一个类而不是多个类。再举一个例子,考虑在Java中用相同的泛型类重载方法会失败:
public void doSomething(List<One>);
public void doSomething(List<Two>);
可整流类型(至少在C#中)可被视为不利的原因是它们导致代码爆炸。例如,List<int>是一个类,而a List<double>是另一个完全不同的类,因为它是a List<string>和a List<MyType>。因此,必须在运行时定义类,这会导致类爆炸,并在生成类时消耗宝贵的资源。
关于不可能new T()在Java中定义的事实(在另一个答案中提到),考虑到这不仅是类型擦除问题,也很有趣。它还需要存在默认构造函数,因此C#为此需要“新约束”。(请参阅Alex Buckley撰写的Java为什么无法在Java中使用new T())。
类型擦除的缺点是您在运行时不知道泛型的类型。这意味着您不能对它们应用反射,也不能在运行时实例化它们。
您无法在Java中执行以下操作:
public class MyClass<T> {
private T t;
//more methods
public void myMethod() {
//more code
if (someCondition) {
t = new T();//illegal
} else {
T[] array = new T[];//illegal
}
}
}
有一种解决方法,但是需要更多代码。正如您所提到的,它的优点是向后兼容。
删除泛型的另一个优点是,编译到JVM的不同语言对泛型采用了不同的策略,例如Scala的定义站点与Java的使用站点协方差。同样,Scala的种类繁多的泛型在.Net的类型化类型上更难支持,因为从本质上讲,.Net上的Scala忽略了C#不兼容的形式化格式。如果我们在JVM中使用通用化泛型,那么这些通用化泛型很可能不适合我们真正喜欢Scala的功能,而我们会陷入次优状态。引用Ola Bini的博客,
这一切的意思是,如果您要向JVM添加经过修饰的泛型,则应该非常确定该实现可以包含所有希望在其自己的泛型版本中进行创新的静态语言,以及所有想要对自己的泛型进行创新的动态语言。与Java库一起创建良好的实现和良好的接口工具。因为如果添加了不满足这些条件的通用化泛型,则会扼杀创新并使使用JVM作为多语言VM变得更加困难。
就我个人而言,我不认为将TypeTagScala中绑定的上下文用于冲突重载方法的必要性是不利的,因为这将使整体化的开销和僵化性从全局(整个程序和所有可能的语言)转移到每种语言的使用位置问题只是这种情况不那么频繁。
Ts,Class<T>对于所有Ts ,您只会得到一个代码副本;对于类型 s,您只会得到一个代码副本。以及实际使用的每种值类型 的附加副本T。