开发者

Java, implicit and explicit type casting of lists of generic enabled objects

I've always wondered about a thing when working with Java and databases. I use a database abstraction layer and get my results like this:

Hashtable h = connection.selectRow("select * from table where id = 5");

However, when returning a number of rows in the same format, it returns this:

ArrayList<Hashtable> a = connection.selectAll("select * from table where id > 5");

Now, as I like generics, I wanted to take full advantage of it by using

ArrayList<Hashtable<String,String>> a = connection.selectAll("select * from table where id > 5");

But this will not compile:

Cannot convert from ArrayList<Hashtable> to ArrayList<Hashtable<String,String>>.

However, split up like this, it works:

ArrayList<Hashtable> a = connection.selectAll("select * from table where id > 5");
Hashtable<String,String> h = a.get(0);

This only produces a type safety warning:

Type safety: The expression of type Hashtable needs unchecked conversion to conform to Hashtable<String,String>.

It seems as if the one step above would do the same as these two lines here, but mashed together into one Java refuses to do the conversion. I suspect some internal mechanism responsible for this behaviour, but have yet to find the reason.

Would anyone care to elaborate?

Edit: Just to clarify. When in my example the error message says

Cannot convert from ArrayList<Hashtable> to ArrayList<Hashtable<String,String>>.

when in the lines below, Java seems very capable of the same thing it just told me it cannot do when I use

Hashtable<String,String> h = a.get(0);

it seems to me that Java is lying to me. Not de开发者_Python百科liberately, of course, we like each other. But there must be a reason. And that's what I'm trying to find out.


The return type of connection.selectAll() is ArrayList<Hashtable>. That's what has to be on the left side.

Because of that, when you say

ArrayList<Hashtable> a = connection.selectAll("select * from table where id > 5");
Hashtable<String,String> h = a.get(0);

You get a warning. a.get(0) is returning a Hashtable (non-generic) and you're assigning it to Hashtable<String,String>.


There are multiple problems / flaws here.

  1. Hashtable is synchronized. Unless there is a real need to have a synchronized map, Hashtables aren't recommended. You could instead use Collections.synchronizedMap for this.

  2. Your entity model is wrong. A Map datastructure shouldn't be used for operations such as these. Instead, you should create an entity for each table. If the table is about employees, create a class called Employee with different attributes mapping to the columns in the database.

  3. The connection.select* methods don't seem to be genericised, meaning you can't just use generics on the left hand side of the method call.

  4. To summarise, the class from which instances of connection objects are created is so not right.


As a temporary solution i think you could actually type your class like

public class yourConnectionClass<E>

in that class you could change the Returntyoe of your method:

public <E> HashMap<E,E> selectAll()

if you now create an object of your class like this:

connection = new yourConnectionClass<String>();

i think this should work so that the returntype of the method should now be Hashmap<String,String>

I really hope that helps.


http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.8

assignment from Vector to Vector<String> is unsafe (since the raw vector might have had a different element type), but is still permitted using unchecked conversion (§5.1.9) in order to enable interfacing with legacy code

raw type support is half-assed; some of simple cases like this are allowed to ease transition.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜