有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中的泛型类型推理(#la C#)

自从我听说类型推断(在Haskell中)以来,我的印象是Java正好相反,即它没有类型推断。不过,最近我有了一个惊喜,意识到Java在其泛型实现中采用了类型推理

然后,我读了Gilad Bracha(据我所知,他是Java中泛型实现的幕后推手之一)的两篇论文。第一篇文章是tutorial about generics(PDF),他在其中明确表示编译器将推断用于替换格式类型参数的实际类型参数。所以,Java中有类型推断,但为什么只针对泛型,为什么不像C#svar关键字那样?这是我向你们提出的问题

为什么Java没有在编译器中内置更多的类型推断

不过,我会提出一个答案,这与我读的第二篇论文有关,Pluggable Type Systems(PDF)。Gilad Bracha似乎认为推理部分不应该是编译器的一部分,而是IDE功能或类似功能(上述论文第4节第6段):

A better engineering approach is to implement type inference as a separate tool, available in the IDE. Programmers who find entering type annotations tiresome can invoke an inferencer on demand.

你觉得怎么样


共 (4) 个答案

  1. # 1 楼答案

    类型推断在IntelliJ中可用,也可能在其他IDE中可用。您可以编写一个表达式(或使用现有的表达式),然后选择“引入字段/局部变量/常量”等,它将为您提供一些类型选项和一些建议的名称。如果表达式多次出现,则可以选择替换所有引用。e、 g.假设我有一个字符串,我想把它变成一个参数

    myMethod();
    
    public void myMethod() {
        "/tmp/20101112/data.file"
    }
    

    我选择日期部分,然后<;ctrl>+&书信电报;alt>+它建议添加一个int类型作为参数。它将把这个日期嵌入所有呼叫者

    myMethod(20101112);
    
    public void myMethod(int date) {
        "/tmp/"+date+"/data.file"
    }
    

    我将“new FileInputStream”(“新文件输入流”)放在开头,并引入一个局部变量。<;ctrl>;+<;alt>;+V

        FileInputStream fileInputStream = new FileInputStream("/tmp/"+date+"/data.file");
    

    它强调了这可能引发一个异常,我可以通过多种方式自动修复该异常。我选择<;alt>+&书信电报;输入>;并将异常添加到方法的throws子句中

    myMethod(20101112);
    
    public void myMethod(int date) throws FileNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("/tmp/"+date+"/data.file");
    

    依我看,让IDE做这项工作更有意义,因为它可以比编译器做得更具交互性,而且你可以明确地看到你的类型变成了什么

  2. # 2 楼答案

    嗯,我认为类型推断在Java中是,主要是因为历史原因:作为一种具有强大遗留约束的语言,Java的改进是谨慎的&;增量(正如JCP所示,即使一些improvements类型推断成功地go through)。对于泛型,长期存在的GJ实现在包含在Java5中之前进行了彻底的评估

    Prior to the release of Java 5, there was no type inference in Java. (...) When generics (...) were introduced in Java 5, the language retained this requirement for variables, methods, and allocations. But the introduction of polymorphic methods (parameterized by type) dictated that either (i) the programmer provide the method type arguments at every polymorphic method call site or (ii) the language support the inference of method type arguments. To avoid creating an additional clerical burden for programmers, the designers of Java 5 elected to perform type inference to determine the type arguments for polymorphic method calls. (source)

    但这并不意味着Java中存在一种强大的普及类型推断文化。根据the spec

    Note also that type inference does not affect soundness in any way. If the types inferred are nonsensical, the invocation will yield a type error. The type inference algorithm should be viewed as a heuristic, designed to perform well in practice. If it fails to infer the desired result, explicit type parameters may be used instead.

    我确实认为,对Java进行更多类型推断将是一件好事(Scala已经是这个方向上的一个very interesting improvement)。总之,类型推断使类型检查器的反馈循环不那么机械,同时又像一样健全,让你写的类型更少,但让你的类型检查也一样多。由于类型的一个主要好处是指导程序搜索的心理过程(“letting you write within the space of well-typed programs, rather than in the space of ascii turds”),与类型检查器交互时的这种舒适感似乎是无价的:你可以有一个类型检查器来验证你用类型良好的术语思考,并训练你这样做,而不是让你在每一行都解释它

    现在,类型推断应该发生在哪个阶段是另一个问题。我认为,想要将“推理器”与运行时分离,可以解决遗留问题:它避免了要求您拥有始终向后兼容的类型推理算法。但关键是你的标准/主要库是什么样子的:你发布的源是什么;是否与他人交换注释

    尽管带注释的源代码确实可以进行类型检查,无论推理引擎的强度如何,这是有价值的,但我仍然希望编译器中有一个类型推理器,因为我不仅不想List<CacheDecoratorFactory> cacheDecoratorFactories = new ArrayList<CacheDecoratorFactory>();,而且不想它。在重构已有的源代码时,我也不想处理它。在与源代码交互之前,我需要一个类型“隐藏”擦除注释,但是如果类型推理引擎没有完成,那么要擦除哪个注释的问题,以及确保在类型重建之后的擦除是双射变得棘手(尤其是如果你的推理引擎没有返回principal type)。。。如果我们必须解决一个棘手的问题,为什么不把它变成一个好的、尽可能完整的类型推理算法呢?我的直觉是,超过一定的质量水平(特别是在返回类型的通用性方面),遗留问题将开始消失

  3. # 3 楼答案

    这并不是一个真正的答案,但从另一方面来说,你可能想看看D语言。它允许您编写如下代码:

    int*[6]*[wstring][]*[string]*[] myVar;
    auto myVar2 = new typeof(myVar[0])[100]; // equivalent to: new int*[6]*[wstring][]*[string]*[]*[string]*[100]
    

    基本上,它是手动推理+自动推理,它可以让你编写非常通用的代码,用其他语言编写起来更困难。(这里的例子不太现实,但它说明了这一点。)

  4. # 4 楼答案

    这是一个有趣的、非常有趣的话题,更多地与研究有关,而不是与实际(即当前)编程有关

    第一件事。关于Java中的var,实际上没有理由实现它,他们已经有了“技术”。然而,泛型只在系统的编译器端,这意味着在运行时VM只使用对对象的引用,并且由于编译器(同样在编译时)注入的代码,它们被适当地强制转换。然而,在C#中,泛型在编译后仍然有效

    其次,关于Bracha的那篇(非常有趣的)论文,你可能应该看看我们的StaDyn项目,一种类似C#的编程语言。类型系统实际上是可插入的,也就是说,您可以像在普通C#中一样使用它,或者根本不使用它,体验一种完全动态的语言

    http://www.reflection.uniovi.es/stadyn/