Generics and anonymous classes (bug or feature?)
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?
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
Foo fooImpl = new Foo(){
public void doFoo() { }
};
List<Foo> f2 = bar(fooImpl); //compiles
}
}
A third option, because I like the syntax and I think it's underused (and probably not that well known), is to explicitly specific the generic parameter on the method call, as follows:
List<? extends Foo> f = <Foo>bar(new Foo(){
public void doFoo() { }
});
It looks better (IMHO) when you have an explicit object that the method's being called on, e.g. this.<Foo>bar(...)
.
No, that's correct. Look at the type of the expression you're passing into bar
in each case. The first time, you're passing in an anonymous type - so the return type is List<anonymous type>
. The second time, you're passing in Foo
(so Foo
is the type argument), so the return type is List<Foo>
.
You could make the first form work if you changed it to:
List<? extends Foo> f = bar(new Foo(){
public void doFoo() { }
});
or
List<Foo> f = bar((Foo) new Foo(){
public void doFoo() { }
});
To leave anonymous types out of it, it's the same difference as:
List<Object> objects = bar("hello"); // Won't compile
vs
Object x = "hello";
List<Object> objects = bar(x); // Will compile
Or, as Andrzej showed, use an explicit type argument.
It doesn't compile because:
new Foo() {
public void doFoo() { }
}
creates an anonymous subclass. It's a different type. You need to explicitly specify the type in that case:
List<Foo> f = bar((Foo)new Foo(){ //A
public void doFoo() { }
}); //don't compiles
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
}
}
You have created anonymous inner class, but anonymous classes are outer class subclasses as you can see above.
IMHO it is not Bug or Feature, but something where you have know what is underhood ;)
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
When you use "doubly brace" you get the same compilation errors.
精彩评论