I'm refatoring a home-grown开发者_开发百科 DAO container, hoping to make the class generic. It internally uses an ArrayList
to store the retrieved objects.
One usage of this class puts the container's list into a request scope, and due to a limitation of Websphere, I can't pass the generic List<Foo>
to the request scope (Websphere doesn't handle generics out-of-the-box)
If I go ahead with my refactorings, I will need to convert/cast the List<Foo>
into a non-generic List
object..
// Boils down to this...
List<Foo> listFoo = new FooListing().findAllFoo();
List listThings = listFoo;
request.setAttribute("listThings", listThings);
What are the implications of reversing a generification like this? Should I avoid doing this kind of manipulation?
EDIT: The code snippet is verbose to explicitly demonstrate what I'm describing..
If the component type of the List does match the expected type, there is no problem.
Generics in Java are only used for type-checks by the compiler, they have not effect at runtime. If you are using an older library that does not support generics, you have no choice but to ignore the generic type. Things should continue to work, as this system has been designed with backwards compatibility in mind.
So all you are losing is the compile-time type checking (it puts you back to where Java was at 1.4, which means, if the types match, everything will work, if not, you'll get ClassCastExceptions or other unwanted behaviour at runtime).
However, I think you can just write
request.setAttribute("listThings", listFoo);
This method takes any kind of Object. Even if it wanted a List, you could still pass a List<Foo>
(which is still a List).
Java uses "type erasure" for generics -- essentially that means that the compiler checks the generics, but the runtime forgets all about it and just treats it as a list of objects.*
Whenever you treat a List<Foo>
as just a List, you won't get compiler checks to make sure you don't put a Bla into your list. So you could get a ClassCastException if you call List<Foo>.get()
and it turns out to be a Bla hiding in the list. But that can only happen if you some code puts a Bla in your list.
If you wan't to be cautious, then if you pass the List<Foo>
as a List to anything that might add a non-Foo to the list, don't treat it as a List<Foo>
whenever you access it, but treat it as a list of Objects
and add instanceof checks.
*Some of the information is accessible at runtime, but let's not complicate matters.
A "non-generic" version of a generic type is called a "raw type".
Passing a generic type where the raw equivalent is requested is generally ok. This is actually the main reason generics in Java work the way they do (with erasure): to enable interoperability between "generified" code and pre-generics code.
The main thing you need to be careful about is that if you pass a List<Foo>
to something that askes for a List
, they may put non-Foo
objects into the List
. You won't get any compile time checking to help you here. You do get some runtime checks: a ClassCastException
will be thrown when you use a method that returns a Foo
on your List<Foo>
and it has to return a non-Foo
.
If you want more fail-fast behavior you can wrap your List<Foo>
with Collections.checkedList()
to get a List that'll check the type of elements on insertion.
Things get more complicated if Foo
itself is a generic type. Runtime checks are only done on reified types (ie: the type with generic type parameters removed) so if you give them a List<Set<Bar>>
and they insert a Set<Baz>
or just a Set
, you won't know since the runtime/reified type of the element is Set
either way.
First, you can't cast a generic to a non-generic list so yeah you'd have to convert it.
Second, the two main advantages to a generic list are 1) it ensures that all objects are of the specified type and 2) it allows you to directly access methods of the object collection without needing to recast them. This allows you to write cleaner code and saves some processing cycles from having to cast back and fourth.
Neither one of these advantages is a dire need however. If you can't use them you won't notice a difference in performance. Your code may look a little messier though.
I have similar problems with Weblogic Portal. Just use none-generic type for this case.
精彩评论