相关疑难解决方法(0)

泛型返回类型上限 - 接口与类 - 令人惊讶的有效代码

这是来自第三方库API的真实示例,但已简化.

使用Oracle JDK 8u72编译

考虑这两种方法:

<X extends CharSequence> X getCharSequence() {
    return (X) "hello";
}

<X extends String> X getString() {
    return (X) "hello";
}
Run Code Online (Sandbox Code Playgroud)

两者都报告了"未经检查的演员"警告 - 我明白了.困扰我的是我为什么打电话

Integer x = getCharSequence();
Run Code Online (Sandbox Code Playgroud)

它编译?编译器应该知道Integer没有实现CharSequence.打电话给

Integer y = getString();
Run Code Online (Sandbox Code Playgroud)

给出错误(如预期的那样)

incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么这种行为被认为是有效的?它会有用吗?

客户端不知道此调用是不安全的 - 客户端的代码在没有警告的情况下编译.为什么编译器不会警告/发出错误?

另外,它与这个例子有什么不同:

<X extends CharSequence> void doCharSequence(List<X> l) {
}

List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles

List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // …
Run Code Online (Sandbox Code Playgroud)

java generics java-8

170
推荐指数
2
解决办法
3万
查看次数

为什么这个通用代码在java 8中编译?

我偶然发现了一段代码,让我想知道为什么它成功编译:

public class Main {
    public static void main(String[] args) {
        String s =  newList(); // why does this line compile?
        System.out.println(s);
    }

    private static <T extends List<Integer>> T newList() {
        return (T) new ArrayList<Integer>();
    }
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果我修改方法的签名newList<T extends ArrayList<Integer>>它不工作了.

注释和响应后更新: 如果我将泛型类型从方法移动到类,则代码不再编译:

public class SomeClass<T extends List<Integer>> {
    public  void main(String[] args) {
        String s = newList(); // this doesn't compile anymore
        System.out.println(s);
    }

    private T newList() {
        return (T) new ArrayList<Integer>();
    }
}
Run Code Online (Sandbox Code Playgroud)

java generics compiler-errors java-8

42
推荐指数
3
解决办法
4254
查看次数

为什么Java 8泛型类型推断选择了这个重载?

考虑以下程序:

public class GenericTypeInference {

    public static void main(String[] args) {
        print(new SillyGenericWrapper().get());
    }

    private static void print(Object object) {
        System.out.println("Object");
    }

    private static void print(String string) {
        System.out.println("String");
    }

    public static class SillyGenericWrapper {
        public <T> T get() {
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它在Java 8下打印"String",在Java 7下打印"Object".

我原以为这是Java 8中的歧义,因为两种重载方法都匹配.为什么编译器print(String)JEP 101之后选择?

是否合理,这会破坏向后兼容性,并且在编译时无法检测到更改.升级到Java 8后,代码只是偷偷摸摸地表现不同.

注意:由于SillyGenericWrapper某种原因,它被命名为"愚蠢".我试图理解为什么编译器的行为方式,不要告诉我这个愚蠢的包装器首先是一个糟糕的设计.

更新:我还尝试在Java 8下编译和运行示例,但使用的是Java 7语言级别.这种行为与Java 7一致.这是预期的,但我仍然觉得需要验证.

java generics language-lawyer java-8

35
推荐指数
2
解决办法
6211
查看次数

Java类型推断:Java 8中的引用不明确,但Java 7则不然

假设我们有2节课.一个空类Base,以及该类的子类Derived.

public class Base {}

public class Derived extends Base {}
Run Code Online (Sandbox Code Playgroud)

然后我们在另一个类中有几个方法:

import java.util.Collection

public class Consumer {

    public void test() {
        set(new Derived(), new Consumer().get());
    }

    public <T extends Base> T get() {
        return (T) new Derived();
    }

    public void set(Base i, Derived b) {
        System.out.println("base");
    }

    public void set(Derived d, Collection<? extends Consumer> o) {
        System.out.println("object");
    }

}
Run Code Online (Sandbox Code Playgroud)

这在Java 7中成功编译并运行,但不能在Java 8中编译.错误:

Error:(8, 9) java: reference to set is ambiguous
  both method set(Base,Derived) in Consumer …
Run Code Online (Sandbox Code Playgroud)

java generics type-inference compiler-errors java-8

26
推荐指数
2
解决办法
5277
查看次数