泛型和匿名类(是bug还是特性?)

3

This code not compiles, because of 'A' expression. It's interesting thing: in A expression expected

List<Foo>
generic type, but got
List<anonymous Foo> 
(according compiler). Is it a jdk bug or feature?

 
接口 Foo{ void doFoo(); }

public class GenericsTest {
public static<V> List<V> bar(V v){ return new ArrayList<V>();}
public static void main(String[] args) { // 下面这一行代码无法编译,因为 Foo 类型不是一个参数类型 List<Foo> f = bar(new Foo(){ //A public void doFoo() { } });
Foo fooImpl = new Foo(){ public void doFoo() { } };
// 下面这一行代码可以编译,因为 fooImpl 是 Foo 的实现类 List<Foo> f2 = bar(fooImpl); } }
4个回答

5

第三种选择,因为我喜欢这种语法并且认为它被低估了(可能并不是那么出名),就是在方法调用时明确指定泛型参数,如下所示:

    List<? extends Foo> f = <Foo>bar(new Foo(){
        public void doFoo() { }
    });

在我的看法中,当你有一个明确的对象调用方法时,它看起来更好,例如: this.<Foo>bar(...)


哇,现在有Eclipse自动生成或至少建议此选项。我刚刚内联了一个内部类,结果是错误的。没有强制转换,我喜欢它。我用它来处理Guava的Optional<T>,也用于Optional.<Foo>absent() - Maarten Bodewes

4
不,这是正确的。看一下你在每种情况下传递给 bar 的表达式的类型。第一次,你传递的是匿名类型 - 因此返回类型是 List<anonymous type>。第二次,你传递的是 Foo(因此 Foo 是类型参数),因此返回类型是 List<Foo>
如果您将第一种形式更改为以下内容,则可以使其正常工作:
List<? extends Foo> f = bar(new Foo(){
            public void doFoo() { }
        });

或者

List<Foo> f = bar((Foo) new Foo(){
            public void doFoo() { }
        });

不考虑匿名类型,这与以下情况没有区别:

List<Object> objects = bar("hello"); // Won't compile

对比

Object x = "hello";
List<Object> objects = bar(x); // Will compile

或者,就像Andrzej展示的那样,使用显式类型参数。

如果我没有从Andrzej那里找到答案,我本来会点赞的。也许你可以更新答案或者指向Andrzej的解决方案? - Maarten Bodewes
@owlstead:已在底部添加了一个小注释。鉴于Andrzej的答案现在是最佳答案,我认为没有必要重复它或类似的东西。 - Jon Skeet

0

它无法编译,因为:

new Foo() {
  public void doFoo() { }
}

创建一个匿名子类。它是一个不同的类型。在这种情况下,您需要明确指定类型:

List<Foo> f = bar((Foo)new Foo(){ //A
  public void doFoo() { }
}); //don't compiles

0
package theBestTrick;

import java.util.ArrayList;
import java.util.List;

interface Foo{ void doFoo(); }

public class GenericsTest {

    public static<V> List<V> bar(V v){ return new ArrayList<V>();}

    public static void main(String[] args) {
        List<Foo> f = bar(new Foo(){ //A
            public void doFoo() { }
        }); //don't compiles

        System.out.println(new Foo(){ //A
            public void doFoo() { }
        }.getClass());//class theBestTrick.GenericsTest$1 <- THAT'S WHY !!! 

        Foo fooImpl = new Foo(){
            public void doFoo() { }
        };

        List<Foo> f2 = bar(fooImpl); //compiles
    }
}

你已经创建了匿名内部类,但是如上所述,匿名类外部类子类
在我看来,这不是Bug或Feature,而是需要知道底层原理的东西 ;)

    class FooImpl implements Foo{
        public void doFoo() { }
    }

    List<FooImpl> f3 = bar(new FooImpl()); //compiles
    List<FooImpl> f4 = bar(new FooImpl(){{
        System.out.println("I'm anonymous inner class");}}
    ); // not compiles

当您使用“双括号”时,会出现相同的编译错误。


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