为什么擦除会使实现函数类型变得复杂?

时间:2011-09-15 19:49:25

标签: java generics language-design type-erasure

我是从interview with Neal Gafter读到的:

  

“例如,使用Erasure作为泛型的一部分,将函数类型添加到编程语言要困难得多。”

编辑: 另一个我遇到类似陈述的地方是Brian Goetz的message in Lambda Dev mailing list,他说当lambdas只是一个带有句法糖的匿名类时,它们更容易处理:

  

但我对函数类型的反对意见并不是我不喜欢函数类型 - 我喜欢函数类型 - 但是函数类型与Java类型系统的现有方面,擦除有很大关系。删除的功能类型是两个世界中最糟糕的。所以我们从设计中删除了它。

任何人都可以解释这些陈述吗?为什么我需要lambdas的运行时类型信息?

4 个答案:

答案 0 :(得分:6)

我理解它的方式是,他们认为,由于擦除,采用“功能类型”的方式会很麻烦,例如:在C#中委托,他们只能使用 lambda表达式,这只是单一抽象方法类语法的简化。

C#中的代表:

public delegate void DoSomethingDelegate(Object param1, Object param2);
...
//now assign some method to the function type variable (delegate)
DoSomethingDelegate f = DoSomething;
f(new Object(), new Object());

(此处的另一个示例 http://geekswithblogs.net/joycsharp/archive/2008/02/15/simple-c-delegate-sample.aspx

他们在Project Lambda文档中提出了一个论点:

  

通用类型被删除,这将暴露其他地方   开发人员暴露于擦除。例如,它不会   可能使方法m(T-> U)和m(X-> Y)过载,这将是   混乱。

第2节: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html

(最终的lambda表达式语法与上面的文档略有不同: http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html

(x, y) => { System.out.printf("%d + %d = %d%n", x, y, x+y); }

总而言之,我最好的理解是,只有部分语法内容可以实际使用。 Neal Gafter最有可能的意思是,无法使用委托将使标准API更难以适应功能样式,而不是javac / JVM更新将更难完成。

如果有人比我更了解这一点,我会很乐意阅读他的帐户。

答案 1 :(得分:2)

Goetz扩展了State of the Lambda 4th ed.中的推理:

  

功能类型的替代(或补充)方法,   一些早期提案建议,本来应该引入一个新的,   结构功能类型。类似“来自字符串和函数的函数”   对象为int“可以表示为(String,Object) - > int。这个   由于有几个想法,至少目前已经考虑并拒绝了这个想法   缺点:

     
      
  • 这会增加类型系统的复杂性,并进一步混合结构和名义类型。
  •   
  • 这将导致库样式的分歧 - 一些库将继续使用回调接口,而其他库将使用结构   功能类型。
  •   
  • 语法可能不合适,尤其是在包含已检查的异常时。
  •   
  • 不太可能存在每个不同函数类型的运行时表示,这意味着开发人员将进一步暴露   并且受到擦除的限制。例如,它是不可能的(也许是   令人惊讶地)重载方法m(T-> U)和m(X-> Y)。
  •   
     

所以,我们选择走“使用你的道路”   知道“ - 因为现有的库广泛使用功能接口,   我们编纂并利用这种模式。

     

为了说明,这里是Java SE 7中的一些功能接口   非常适合与新语言功能一起使用;   以下示例说明了其中一些示例的使用。

     
      
  • 了java.lang.Runnable
  •   
  • java.util.concurrent.Callable
  •   
  • 了java.util.Comparator
  •   
  • 的java.beans.PropertyChangeListener
  •   
  • java.awt.event.ActionListener
  •   
  • javax.swing.event.ChangeListener
  •   
  • ...
  •   

请注意,擦除只是其中一个考虑因素。一般来说,Java lambda方法与Scala的方向不同,而不仅仅是键入的问题。它是以Java为中心的。

答案 2 :(得分:1)

也许是因为你真正想要的是一个类型Function<R, P...>,它使用返回类型和一些参数类型参数化。但是由于擦除,你不能拥有像P...那样的构造,因为它只能变成Object[],这太松散了,不能在运行时使用。

这是纯粹的猜测。我不是一个理论家;我甚至没有在电视上播放过。

答案 3 :(得分:-1)

我认为他在该声明中的意思是在运行时Java无法区分这两个函数定义:

void doIt(List<String> strings) {...}
void doIt(List<Integer> ints) {...}

因为在编译时,有关List包含的数据类型的信息将被删除,因此运行时环境将无法确定您要调用哪个函数。

尝试在同一个类中编译这两个方法将引发以下异常:

doIt(List<String>) clashes with doIt(List<Integer); both methods have the same erasure