为什么方法参数和通配符不能互换?

时间:2018-01-05 14:39:23

标签: java generics

我认为参数和通配符占位符大致具有相同的含义,其中第一个用于定义类和方法,第二个用于声明变量。但显然事实并非如此。

import java.util.List;
import java.util.function.Consumer;

public class Main {

    public static void main(String[] args) {
        Consumer<List<? extends Number>> l1 = null;
        Consumer<List<? extends Number>> l2 = null;

        l1 = l2;    // compiles
    }

    static <T extends Number> void m(Consumer<List<T>> l) {
        Consumer<List<? extends Number>> l3 = l; // doesn't compile
    }
}

我认为该行Consumer<List<? extends Number>> l3 = l应该与l1 = l2;一样。但事实并非如此。有人可以解释为什么这个样本不能编译,我该如何解决这个问题。

1 个答案:

答案 0 :(得分:0)

Consumer<List<T>>不是Consumer<List<? extends Number>>的子类型,即使List<T>List<? extends Number>的子类型,就像Foo<Dog>不是子类型Foo<Animal>一样Dog即使AnimalConsumer<? extends List<? extends Number>> l3 = l; 的子类型。

通用类型参数是不变的,这意味着(除非您在顶层有通配符),它们必须与完全匹配。如果您希望它与不同的类型参数兼容,您必须在顶层有一个通配符,如下所示:

static void m(Consumer<? extends List<? extends Number>> l3)

或者您可以将方法声明为

Consumer

它将接受之前接受的所有论据。

(但是,我想指出,使用T声明的方法实际上没有任何意义。您的方法在List<T>上是通用的,并且它接收消费者的内容List<T>。您的方法几乎没有办法使用此消费者,因为您的方法必须将T传递给它,但您的方法不知道T是什么,并且它没有T类型的其他参数或任何其他方式来确定List<T>是什么或得到<?php $servername = "localhost"; $username = "myusername"; $password = "mypassword"; $dbname = "mydb"; // Create connection /* was $conn */ $mysqli = new mysqli($servername, $username, $password, $dbname); // Check connection // change $conn tp $mysqli if ($mysqli->connect_error) { die("Connection failed: " . $conn->connect_error); } $mysqli->set_charset("utf8"); if (isset($_REQUEST['q'])){ $target= $_REQUEST['q']; $sql = " SELECT * FROM TABLE1 WHERE name LIKE '%$target%'"; $result = $mysqli->query($sql) or die($mysqli->error . "<pre>$sql</pre>"); while ($row = $result->fetch_assoc()){ echo $row["number"] . " " . $row["name"]. " " . $row["hp"] . "<br>"; } } else { echo "0 results"; } ?> ,所以它唯一可以安全传入的是一个空列表。所以您的方法可以使用此使用者的唯一方法是将其传递给空列表,这可能不是很有用。)