这个深奥的泛型错误是编译器错误还是新限制? (推断类型不符合上限)

Posted

技术标签:

【中文标题】这个深奥的泛型错误是编译器错误还是新限制? (推断类型不符合上限)【英文标题】:Is this esoteric generics error a compiler bug or a new restriction? (inferred type does not conform to upper bounds) 【发布时间】:2015-07-09 12:26:21 【问题描述】:

我从 Java 8u5 更新到 8u45,一些以前工作的代码不再编译。问题是,发生这种情况的一半时间是故意更改,所以我无法确定这是否是错误。

(我还测试到 u25,每个版本都与 u45 做同样的事情。)

但本质上,它与一个方法的多个返回点有关。例如:

import java.sql.Connection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CompilerIssue

    public Set<String> test(int value)
    
        return perform(connection -> 
            if (value % 2 == 0)
            
                return Collections.<String>emptySet();
            
            else
            
                return new HashSet<>(10);
            
        );
    

    <V> V perform(BusinessLogic<V> logic)
    
        // would usually get a connection
        return null;
    

    interface BusinessLogic<V>
    
        V execute(Connection connection) throws Exception;
    

javac 给出:

Error:(12, 23) java: incompatible types: inferred type does not conform to upper bound(s)
    inferred: java.util.Set<? extends java.lang.Object>
    upper bound(s): java.util.Set<java.lang.String>,java.lang.Object

IDEA,像往常一样,看不出任何问题。

我已经知道解决方法 - 将 HashSet&lt;&gt; 替换为 HashSet&lt;String&gt;。但是我们在代码中普遍使用了这种结构,所以在我花时间彻底改变它之前,我想知道:这是一个错误,还是旧的行为是错误?

(如果是一个错误,那么我必须向 Oracle 报告一个错误。如果它是一个特性,那么我必须向 IDEA 报告一个错误,认为它没问题。)

【问题讨论】:

我也希望Collections.emptySet() 能够工作,但它会导致同样的错误。 @xehpuk 是的,如果使用 Collections.emptySet() 和 new HashSet,你也会得到错误。似乎新行为(错误或其他)是查看每个返回点,但所有返回点都必须是显式的,而旧行为似乎更像相反,您只需要将其中一个显式化即可将暗示其余的。 【参考方案1】:

据我所知,这是一个错误并且来自 Oracle,它没有从目标类型(句子 return 期望返回的类型)正确推断类型,而是以某种方式比较两个 return 句子的上限:(return Collections.&lt;String&gt;emptySet();return new HashSet&lt;&gt;(10);)。

在第二个 return 语句中,new HashSet&lt;&gt;(10) 的上限将是 Object,但类型可以从返回类型推断为确实是 &lt;String&gt;。尝试注释掉第一个 return 语句并返回 null 并编译:

public class CompilerIssue

    public Set<String> test(int value)
    
        return perform(connection -> 
            if (value % 2 == 0)
            
                return null; // COMMENTED OUT FOR TESTING PURPOSES Collections.<String>emptySet();
            
            else
            
                return new HashSet<>(10);
            
        );
    

    <V> V perform(BusinessLogic<V> logic)
    
        // would usually get a connection
        return null;
    

    interface BusinessLogic<V>
    
        V execute(Connection connection) throws Exception;
    

这会编译,它会正确推断出HashSet&lt;&gt;(10) 的正确值类型应该是String

【讨论】:

以上是关于这个深奥的泛型错误是编译器错误还是新限制? (推断类型不符合上限)的主要内容,如果未能解决你的问题,请参考以下文章

值限制 - 该值已被推断为具有泛型类型

请教关于java的泛型方法

请教关于java的泛型方法

Typescript - 确保泛型属性存在于具有描述性错误的泛型类型上

JAVA中的泛型类是啥东西?

你真的了解JAVA中的泛型E、T、K、V吗?