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

标签 java generics compiler-errors 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>();
    }
}

有趣的是,如果我修改方法的签名 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>();
    }
}

最佳答案

如果您在方法中声明类型参数,则您允许调用者为其选择实际类型,只要该实际类型满足约束条件。该类型不必是实际的具体类型,它可能是抽象类型、类型变量或交集类型,换句话说,更通俗地说,是假设类型。所以,as said by Mureinik ,可能有一个类型扩展 String 并实现 List。我们无法手动为调用指定交集类型,但可以使用类型变量来演示逻辑:

public class Main {
    public static <X extends String&List<Integer>> void main(String[] args) {
        String s = Main.<X>newList();
        System.out.println(s);
    }

    private static <T extends List<Integer>> T newList() {
        return (T) new ArrayList<Integer>();
    }
}

当然,newList() 不能满足返回这样一个类型的期望,但这就是这个方法的定义(或实现)的问题。将 ArrayList 转换为 T 时应该会收到“未检查”警告。唯一可能的正确实现是在此处返回 null,这会使该方法毫无用处。

重复最初的陈述,重点是泛型方法的调用者为类型参数选择实际类型。相反,当你声明一个通用的 class 像 with

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>();
    }
}

类型参数是类契约的一部分,因此创建实例的人将为该实例选择实际类型。实例方法 main 是该类的一部分,并且必须遵守该约定。你不能选择你想要的TT 的实际类型已经设置,在 Java 中,你通常甚至无法找出 T 是什么。

泛型编程的关键是编写独立于为类型参数选择的实际类型工作的代码。

但请注意,您可以创建 另一个,具有您喜欢的任何类型的独立实例并调用该方法,例如

public class SomeClass<T extends List<Integer>> {
    public <X extends String&List<Integer>> void main(String[] args) {
        String s = new SomeClass<X>().newList();
        System.out.println(s);
    }

    private T newList() {
        return (T) new ArrayList<Integer>();
    }
}

在这里,新实例的创建者选择该实例的实际类型。如前所述,实际类型不需要是具体类型。

关于java - 为什么这个通用代码在 java 8 中编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38092697/

相关文章:

Java (Grails) 或 Erlang (Elixir) 对短网络请求 : speed, 可扩展性?

Java 类型推断在编译时失败,但 Eclipse 编译并运行得很好

java - 在 Java 中创建一个数组来存储泛型类型

java - Jikes rvm运行时错误 "Could not find the class java.util.Scanner"

java - 95%完成了JAVA阵列代码。谁能帮我找到我的错误?

java - 什么是 premain() 以及它是如何被调用的?

java - 如何将JDialog置于顶部

java - 从弃用的 Blobstore File API 到服务 blob

java - 避免未经检查的强制转换以强制转换为事件发布者的 Java 通用接口(interface)集合

asp.net-mvc - 为什么VS无法识别标准的MVC组件,例如ViewBag,@ Html.ActionLink等?