tags:

views:

84

answers:

1

    class SomeClass<E> {
       Map<String, String> someMethod();
    }

And usage


    SomeClass a = new SomeClass();
    a.someMethod().get("foo") // returns object, not string!

    //This code would not even compile
    String s = a.someMethod().get("foo");

But if I remove generalization (<E>) from SomeClass -- it works.

It also works if I extract this method to interface and use interface in declaration:


    interface Foo {
     Map<String, String> someMethod();
    }

    class SomeClass implements Foo {
    //.....
    }

    Foo foo = new SomeClass();

    String s = foo.someMethod().getString("A");//it works

Why it happens? Where can I read about it? What is the best work-around? Thanks.

+10  A: 

The solution isn't to make SomeClass non-generic - it's to avoid using the raw type. For example, this works fine:

import java.util.*;

class SomeClass<E> {
   Map<String, String> someMethod() {
      return null;
   }
}

public class Test {
    public static void main(String[] args) {
        SomeClass<Integer> a = new SomeClass<Integer>();
        String value = a.someMethod().get("foo");
    }
}

Admittedly it's slightly odd that the method effectively has type erasure applied if you use the raw type - but you should basically avoid doing that to start with.

I can't currently find any explanation for the behaviour of the raw type in the JLS, but section 4.8 does include this warning:

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

Jon Skeet
`SomeClass<?> a = new SomeClass();` also works.
Tim Bender
@Jon, near the end of Chapter 4.8 there's a discussion using classes `NonGeneric` and `RawMember` where they show, that it should work at least for static members (`Collection<NonGeneric>` in class `RawMember`) ... really strange.
Andreas_D
@Andreas_D: I saw that, but I'm not sure it's quite the same situation. It is indeed very strange.
Jon Skeet
My guess is that if you use the raw type the compiler assumes you're trying to write code for pre-1.5 Java, and ignores all generic information withing the (raw) class, even if it's not related to the type parameters of the class. So if you want the generics don't use raw types.
Andrei Fierbinteanu