9

这是讨论的后续问题:

为什么钻石运算符在 Java 7 的 addAll() 调用中不起作用?

从Java教程,

http://docs.oracle.com/javase/tutorial/java/generics/gentypeinference.html

请注意,菱形通常在方法调用中起作用;但是,为了更清楚起见,建议您主要使用菱形来初始化声明它的变量

所以,我对第一行有点困惑。钻石何时在方法调用中起作用

关于钻石运算符如何工作的更多解释可以在这里找到:

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#What%20is%20type%20argument%20inference%20for%20constructors

从此,我尝试了以下方法,效果很好:

给我:

private static class Box<T>{
    public Box(T t){}
}
static void f(Box<Integer> box){}

像下面这样的调用编译得很好:

f(new Box<>(new Integer(10)));

上述方法调用中调用构造函数的类型参数f()是从构造函数的参数推断出来的(即Integer)。

这就是教程说的意思吗

请注意,菱形通常在方法调用中起作用

如果没有,任何人都可以提供一个钻石在方法调用中起作用的例子吗?

4

3 回答 3

3

这就是教程说的意思吗

我认为是的,尽管在<>运营商方面存在一些问题。

在您的情况下, Box 实例化不是问题,因为可以使用构造函数参数轻松推断类型。尝试将构造函数更改为“不”接受IntegerorT并查看调用如何失败。

class BadBox<T> {

    private T t;

    public BadBox(){}    

    public void setT(T t) {
        this.t = t;
    }

    static void f(BadBox<Integer> box){}

    public static void main(final String[] args) {
        f(new BadBox<>());  //fails, should have worked ideally
    }    
}

同样,看看这个类:

class Testi<R> {    
    public void doIt(Set<? extends R> sets) {
    }

    public static void main(final String[] args) {
            // works since type inference is now possible
        new Testi<CharSequence>().doIt(new HashSet<>(Arrays.asList("a")));

            // fails; nothing which can help with type inference
        new Testi<CharSequence>().doIt(new HashSet<>();
    }       
}

同样,您的链接问题(关于addAll)中的问题可以通过如下帮助编译器来简单地解决:

List<String> list = new ArrayList<>();
list.add("A");

// works now! use only if you love diamond operator ;)
list.addAll(new ArrayList<>(Arrays.asList(new String[0])));
// or the old-school way
list.addAll(new ArrayList<String>()));

在实现匿名类时,菱形运算符似乎也中断了,如下所示:

final String[] strings = { "a", "b", "c" };
Arrays.sort(strings, new Comparator<>() {
    @Override
    public int compare(String o1, String o2) {
        return 0;
    }
});

幸运的是,在这种情况下,编译器非常明确地提到<>不能/不会使用匿名类。

于 2011-12-26T17:47:13.867 回答
1

我认为不值得考虑何时有效,何时无效。编译器会告诉你,因此你必须重写什么不起作用。

这背后没有真正的理由。更像是开发人员将实际编译器在特定时间实现的当前限制放入规范中,并告诉我们:必须如此。

Java 8 解除了很多这些限制,而不会死机。例如

Arrays.asList("foo", "bar").addAll(new ArrayList<>());

使用 Java 8 编译没有任何错误。那么为何不?

于 2014-02-05T19:05:17.383 回答
0

这实际上与方法调用无关。独立声明

new Box<>(new Integer(10));

也编译。有足够的信息可以推断TBox即从 Integer 参数)

另一方面,这不会编译

new ArrayList<>();

没有办法知道需要什么样的列表。

Collection<String> strings = new ArrayList<>();

这是有效的,因为目标类型有助于推理Collection<String>

于 2011-12-26T21:29:01.080 回答