Java, implicit and explicit casting of generic object lists

I always wondered about working with Java and databases. I use the database abstraction layer and get my results as follows:

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

However, when returning a series of lines in the same format, it returns this:

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

Now that I like generics, I would like to make full use of it using

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

But this does not compile:

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

However, crashed like this, it works:

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

This only triggers a security warning like:

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

It seems that one step above will do the same as these two lines here, but in one Java refuses to do the conversion. I suspect that some kind of internal mechanism is responsible for this behavior, but has not yet found a reason.

Would anyone like to clarify?

Edit: just clarify. When in my example the error message reports

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

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

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

It seems to me that Java lies with me. Not consciously, of course, we love each other. But there must be a reason. And this is what I am trying to find out.

+4
source share
4 answers

The return type of connection.selectAll() is equal to ArrayList<Hashtable> . This is what should be on the left side.

Because of this, when you say

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

You will receive a warning. a.get(0) returns a Hashtable (not shared), and you assign it to Hashtable<String,String> .

+1
source

There are several problems / drawbacks.

  • Hashtable syncs. Unless there is a real need for a synchronized card, Hashtables are not recommended. Instead, you could use Collections.synchronizedMap .

  • Your entity model is erroneous. The cartographic data structure should not be used for such operations. Instead, you should create an entity for each table. If the table is about employees, create an Employee class with a different attribute matching the columns in the database.

  • The connection.select* methods do not seem to be generic, that is, you cannot just use the generics on the left side of the method call.

  • To summarize, the class from which the connection objects are instantiated is not true.

0
source

As a workaround, I think you can really introduce your class, for example

 public class yourConnectionClass<E> 

in this class, you can modify the returntyoe of your method:

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

if now you create an object of your class as follows:

 connection = new yourConnectionClass<String>(); 

I think this should work so that the return type of the method is now Hashmap<String,String>

I really hope this helps.

0
source

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

from Vector to Vector<String> unsafe (since the original vector could have a different element type), but the use of an unchecked conversion is still allowed (ยง5.1.9) to allow interoperability with legacy code

support for the original type by half; some simple cases like this are allowed to facilitate the transition.

0
source

Source: https://habr.com/ru/post/1343790/


All Articles