tags:

views:

83

answers:

4

Hi. 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
    }
}
 
+2  A: 

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
Jon Skeet
A: 

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
cletus
+1  A: 

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(...).

Andrzej Doyle
A: 
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.

Maciek Kreft