Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-generic reference to generic class results in non-generic return types

Tags:

java

generics

I have a legacy class that the class itself is not a generic but one of its methods return type uses generics:

public class Thing {
    public Collection<String> getStuff() { ... }
}

getStuff() uses generics to return a collection of strings. Therefore I can iterate over getStuff() and there's no need to cast the elements to a String:

Thing t = new Thing();
for (String s: t.getStuff())  // valid
{ ... }

However, if I change Thing itself to be a generic but keep everything else the same:

public class Thing<T> {
    public Collection<String> getStuff() { ... }
}

and then keep using the non-generic reference to Thing, getStuff() no longer returns Collection<String> and instead returns a non-typed Collection. Thus the client code does not compile:

Thing t = new Thing();
for (String s: t.getStuff())  // compiler complains that Object can't be cast to String
{ ... }

Why is this? What are the workarounds?

My guess is that by using a non-generic reference to a generic class, Java turns off all generics for the entire class. This is pain, because now I've broken my client code by making Thing a generic.

Edit: I'm making Thing generic for another method which is not listed in the above example code. My question is educational as to why the above cannot be done.

like image 307
Steve Kuo Avatar asked Jan 16 '09 00:01

Steve Kuo


People also ask

Can a non-generic class have a generic method?

Yes, you can define a generic method in a non-generic class in Java.

Can a non-generic class inherit a generic class?

Yes, in this case, inheritance is a better solution than composition as you have it, because a StackInteger is a Stack .

Which reference type can not be generic?

Almost all reference types can be generic. This includes classes, interfaces, nested (static) classes, nested interfaces, inner (non-static) classes, and local classes. The following types cannot be generic: Anonymous inner classes .

Which of the following problems of non-generic collection does generics solve?

Code reusability: Generics help in reusing the code already written, thereby making it usable for other types (for a method, or class, or an interface).


1 Answers

Ok, take two, I misunderstood your question.

When you delcare Thing (this is called a raw type) instead of Thing<?> (parameterized type) the Java compiler strips out all generic arguments, even thogh (as in your case) the generic type of the method has nothing to do with the generic type of the class.

From the (excellent) Java Generics FAQ:

Can I use a raw type like any other type?

Methods or constructors of a raw type have the signature that they would have after type erasure.

This seemingly inocuous and unobtrusive sentence describes the behaviour in question. You're using Thing as a raw type so the return type is Collection (not Collection<String>) since this is the type after type erasure.

Confused? Not surprising. Just look at the size of that FAQ. There's probably about three people on earth who nderstand the full implications of Java Generics. Just consider my favourite declaration from the JDK:

Enum<T extends Enum<T>> 

(Theres an explanation of that in the FAQ too).

like image 55
cletus Avatar answered Sep 19 '22 16:09

cletus