Java 7中的钻石操作符在方法调用中的应用

9

这是一个关于讨论的后续问题:

为什么在Java 7中diamond操作符在addAll()调用中无法工作?

根据Java教程,

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

请注意,diamond经常在方法调用中起作用;但是,为了更清晰,请主要在声明变量时使用diamond

所以,我有点困惑第一行。在什么情况下diamond在方法调用中起作用?

有关diamond操作符如何工作的更多解释可以在这里找到:

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)推断出类型参数。这是教程所说的钻石语法在方法调用中起作用的意思吗?如果不是,请有好心人提供一个钻石语法在方法调用中起作用的例子。

@gurung 这是一个打字错误。复制和粘贴的问题很严重 :( - Sa'ad
3个回答

3

当教程中提到“<>”运算符时,是否就是指这个意思?

我认为是的,尽管在使用“<>”运算符时有一些需要注意的问题。

在您的情况下,由于类型可以通过构造函数参数轻松推断出来,因此Box实例化不是一个问题。尝试更改构造函数以使其不接受IntegerT,然后查看调用失败的情况。

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

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


1
我认为没有必要考虑什么时候它能正常工作,什么时候不能。编译器会告诉你,因此你需要重写不起作用的部分。
这背后没有真正的理由; 更像是开发人员将实际编译器实现的当前限制放入规范中,并告诉我们:它必须是这样的。
Java 8解除了许多这些限制,而且并没有导致灾难性后果。例如:
Arrays.asList("foo", "bar").addAll(new ArrayList<>());

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


0

这并不是关于方法调用的问题。这是一个独立的语句。

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

同样可以编译。有足够的信息推断出BoxT(即从整数参数)

另一方面,这个不能编译

new ArrayList<>();

无法知道所需的列表类型。

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

这个方法可行是因为目标类型Collection<String>帮助了推断。


1
new ArrayList<>(); 作为一个独立的语句是可以编译通过的。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接