2

I should know this, but I can't understand this for some reason.

Why can I not cast a List of Objects List<Object> to a List of Maps List<Map<String, Object>>? Every object in the list is an object of type Map<String, Object>, so why is the casting not possible?

What I can do is create a new ArrayList<Map<String, Object>>(); and iterate over the list and add each item with a cast.

List<Object> dataList;
..
//Why doesn't this work?
List<Map<String, Object>> rxData = (List<Map<String, Object>>)dataList;

//This works, but is there a better way?
rxData = new ArrayList<Map<String, Object>>();
for (Object data : dataList) {
    rxData.add((Map<String, Object>)data);
}
Andy
  • 2,469
  • 1
  • 25
  • 25
  • Why? Because Java's generics aren't refiable. There's no way for the JVM to actually check the cast is correct. If you just want to do it anyway, I think `@SuppressWarnings("unchecked")` is the solution, though I didn't test that. – markspace Aug 15 '16 at 22:37
  • 1
    Java generics FAQ: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#What%20is%20the%20SuppressWarnings%20annotation? – markspace Aug 15 '16 at 22:39

3 Answers3

5

You can just drop generic parameter by double-casting:

@SuppressWarnings("‌​unchecked")
List<Map<String, Object>> rxData = 
    (List<Map<String, Object>>) (List<?>) dataList;

What is going here is that you force compiler to not to check generic type by omitting it with first cast and then do unchecked cast to List<Map<String, Object>>. This is possible because java generics is non-refiable.

The original error is caused by fact that Object is not compatible with Map<> type and there is no such thing like covariant/contravariant types in java (unlike scala for example).

But there gonna be a problems if dataList contains not maps.

vsminkov
  • 10,912
  • 2
  • 38
  • 50
  • 2
    No need for a raw type here, and the problem is not related to reifiablity. – k5_ Aug 15 '16 at 22:46
  • @k5_ agree. thanks! but anyway that will be unchecked cast. I'll edit my answer – vsminkov Aug 15 '16 at 22:47
  • Thank you! OK, I think I understand, and I need to careful so that the list does not contain anything besides maps. – Andy Aug 15 '16 at 22:53
  • 2
    You should remove the first sentence of your answer, or move it later in the answer: it's true, but not very relevant. (Non-reifiability is why a cast from `List>` to `List>` is unchecked; but it has nothing to do with why you can't cast from `List` to `List>`.) – ruakh Aug 15 '16 at 22:54
  • @ruakh you are right. thank you! I'll edit my answer – vsminkov Aug 15 '16 at 22:58
  • Per Joshua Bloch, if you must use `@SuppressWarnings("‌​unchecked")`, then you must also comment the code there documenting how it is that you are certain that the cast is safe. – Lew Bloch Aug 16 '16 at 01:13
  • @LewBloch: I agree; though note that this cast actually *isn't* safe in the way that Joshua Bloch means, so instead of a comment documenting why it's safe, it should have a comment documenting why it's being used despite not being safe. – ruakh Aug 17 '16 at 19:51
4

List<Object> and List<Map<String, Object>> are not compatible types, therefore you can't directly cast one to the other. You would have to first cast to to a common supertype and then downcast:

List<Map<String, Object>> rxData = (List<Map<String, Object>>)(List<?>)dataList;

Note that you'll still get a warning at compile time, because it's an unsafe cast.

Community
  • 1
  • 1
shmosel
  • 49,289
  • 6
  • 73
  • 138
0

Check following link

https://docs.oracle.com/javase/tutorial/java/generics/inheritance.html

Two generic classes Type1 and Type2 aren't related at all. So you can't typecast one to another.

However you can do some unsafe operations and save yourself from the loop.

//unsafe assignments
List rxData = (List<Map<String, Object>>)dataList;

List<Object> dataList = (List<Object>)rxData;
11thdimension
  • 10,333
  • 4
  • 33
  • 71