135

This does not compile, any suggestion appreciated.

 ...
  List<Object> list = getList();
  return (List<Customer>) list;

Compiler says: cannot cast List<Object> to List<Customer>

skaffman
  • 398,947
  • 96
  • 818
  • 769
user198313
  • 4,228
  • 6
  • 24
  • 19

17 Answers17

185

you can always cast any object to any type by up-casting it to Object first. in your case:

(List<Customer>)(Object)list; 

you must be sure that at runtime the list contains nothing but Customer objects.

Critics say that such casting indicates something wrong with your code; you should be able to tweak your type declarations to avoid it. But Java generics is too complicated, and it is not perfect. Sometimes you just don't know if there is a pretty solution to satisfy the compiler, even though you know very well the runtime types and you know what you are trying to do is safe. In that case, just do the crude casting as needed, so you can leave work for home.

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • 15
    This also needs `@SuppressWarnings("unchecked")`. Note that you can also upcast to `(List)` instead of to `(Object)`. – 200_success Feb 15 '16 at 11:12
40

Depending on your other code the best answer may vary. Try:

List<? extends Object> list = getList();
return (List<Customer>) list;

or

List list = getList();
return (List<Customer>) list;

But have in mind it is not recommended to do such unchecked casts.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 3
    -1 - this is a really bad habit to get into, and unless you use the "Unchecked" annotation, the compiler will still complain about it – kdgregory Dec 16 '09 at 21:37
40

With Java 8 Streams:

Sometimes brute force casting is fine:

List<MyClass> mythings = (List<MyClass>) (Object) objects

But here's a more versatile solution:

List<Object> objects = Arrays.asList("String1", "String2");

List<String> strings = objects.stream()
                       .map(element->(String) element)
                       .collect(Collectors.toList());

There's a ton of benefits, but one is that you can cast your list more elegantly if you can't be sure what it contains:

objects.stream()
    .filter(element->element instanceof String)
    .map(element->(String)element)
    .collect(Collectors.toList());
Squake
  • 370
  • 2
  • 10
roundar
  • 1,593
  • 1
  • 18
  • 22
  • 4
    That's more of a copy than a cast, though. – 200_success Feb 15 '16 at 11:15
  • The casting mentioned in the accepted anser didn't work for me. Also I was on Java 7. But Guava's `FluentIterable` worked for me. – Sridhar Sarnobat Nov 02 '17 at 23:05
  • This is what I was looking for, I just didn't know the syntax – Fueled By Coffee Mar 28 '18 at 17:57
  • This is not working for me. I get error **java.lang.ClassCastException: class java.lang.Object cannot cast to class my.package.MyInterface. java.lang.Object is in module java.base of loader bootstrap; my.package.MyInterface is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.restartClassLoader** – cd491415 Oct 17 '21 at 21:57
37

That's because although a Customer is an Object, a List of Customers is not a List of Objects. If it was, then you could put any object in a list of Customers.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 3
    No, it isn't. You would circumvent type safety if the above was allowed. Note that casting does not mean create a new list and copy over the items. It means handle the single instance as a different type, and thus you would have a list that contains potentially non-Customer objects with a type safety guarantee that it shouldn't. This has nothing to do with java as such. Since you feel that this feature leaves Java stuck in the dark ages, I challenge you to explain how you think this should work instead. – Lasse V. Karlsen Sep 26 '14 at 09:31
  • 1
    @BrainSlugs83 for your need (List)(Object)list; – Muthu Ganapathy Nathan Oct 31 '14 at 12:40
  • @LasseV.Karlsen I'm not talking about casting, I'm talking about converting. It would not circumvent type safety, it would enforce it. Java's implementation of generics, lack of operator overloads, extension methods, and many other modern amenities has left me epically disappointed. -- Meanwhile, .NET has two separate extension methods for this -- one called `.Cast()` and one called `.OfType()`. The former performs a cast on each element (throwing the desired exceptions) while the latter filters out elements that can't be cast (so you would pick one depending on your usage scenario). – BrainSlugs83 Oct 31 '14 at 22:14
  • 1
    @EAGER_STUDENT I wouldn't put it past Java that that might actually work (all this ridiculous type erasure business, I'd have to try it ...) -- but no, I would never write code like that -- you lose type safety, what happens if one element in the collection is not an `instanceof` Customer? – BrainSlugs83 Oct 31 '14 at 22:18
  • 2
    @BrainSlugs83 The person that asked the question specifically asked about casting. And if Java doesn't already have the relevant methods like the .NET methods you refer to (which still isn't converting btw), then you should easily be able to add them. This is all kinda orthogonal to the question at hand though, which asked about specific syntax. – Lasse V. Karlsen Oct 31 '14 at 23:29
29

You can use a double cast.

return (List<Customer>) (List) getList();
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
15

Another approach would be using a java 8 stream.

    List<Customer> customer = myObjects.stream()
                                  .filter(Customer.class::isInstance)
                                  .map(Customer.class::cast)
                                  .collect(toList());
d0x
  • 11,040
  • 17
  • 69
  • 104
7

Note that I am no java programmer, but in .NET and C#, this feature is called contravariance or covariance. I haven't delved into those things yet, since they are new in .NET 4.0, which I'm not using since it's only beta, so I don't know which of the two terms describe your problem, but let me describe the technical issue with this.

Let's assume you were allowed to cast. Note, I say cast, since that's what you said, but there are two operations that could be possible, casting and converting.

Converting would mean that you get a new list object, but you say casting, which means you want to temporarily treat one object as another type.

Here's the problem with that.

What would happen if the following was allowed (note, I'm assuming that before the cast, the list of objects actually only contain Customer objects, otherwise the cast wouldn't work even in this hypothetical version of java):

List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];

In this case, this would attempt to treat an object, that isn't a customer, as a customer, and you would get a runtime error at one point, either form inside the list, or from the assignment.

Generics, however, is supposed to give you type-safe data types, like collections, and since they like to throw the word 'guaranteed' around, this sort of cast, with the problems that follow, is not allowed.

In .NET 4.0 (I know, your question was about java), this will be allowed in some very specific cases, where the compiler can guarantee that the operations you do are safe, but in the general sense, this type of cast will not be allowed. The same holds for java, although I'm unsure about any plans to introduce co- and contravariance to the java language.

Hopefully, someone with better java knowledge than me can tell you the specifics for the java future or implementation.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 3
    The future of Java is... Scala. Seriously, the guy who bolted generics onto Java has developed a new language that's vaguely similar to Java but really, really proficient with types: A very thorough and consistent implementation of type handling. I think no one knows for certain which Scala features will flow back into Java, and when. – Carl Smotricz Dec 16 '09 at 21:57
  • an excellent explanation of covariance that truly answers the OPs question. Well done. – Kevin Day Dec 17 '09 at 03:50
  • Carl: I thought some Java devs went ahead to create C#? :) Anyway yeah, Java is most likely going to the direction of Scala in the future instead of, say, something less strongly typed. – Esko Dec 18 '09 at 06:51
  • @Carl - in Scala there's a subtle difference in that by default Lists are immutable. So generally yo don't have the problem of adding an Object to a list of Customers, since when you do this you get a *new* list of *Objects*. – Brian Agnew Feb 14 '10 at 18:43
  • Er... technically this is correct -- but even before .NET 4.0 -- you could do this with regular IEnumerable extension methods (.Cast<> and .OfType<>) -- so no need to go off the deep end if you just want strong type iteration. – BrainSlugs83 Sep 26 '14 at 07:27
  • Technically that is correct, but that won't give you a `List`, which is what the OP asked for help with. You can't do what the OP asked for, but obviously there are workarounds if you can live with something that isn't a `List`. – Lasse V. Karlsen Sep 26 '14 at 09:29
4

You can do something like this

List<Customer> cusList = new ArrayList<Customer>();

for(Object o: list){        
    cusList.add((Customer)o);        
}

return cusList; 

Or the Java 8 way

list.stream().forEach(x->cusList.add((Customer)x))

return cuslist;
Kalana Demel
  • 3,220
  • 3
  • 21
  • 34
Malkeith Singh
  • 235
  • 1
  • 8
3

You should just iterate over the list and cast all Objects one by one

vrm
  • 1,312
  • 4
  • 20
  • 28
2

You can't because List<Object> and List<Customer> are not in the same inheritance tree.

You could add a new constructor to your List<Customer> class that takes a List<Object> and then iterate through the list casting each Object to a Customer and adding it to your collection. Be aware that an invalid cast exception can occur if the caller's List<Object> contains something that isn't a Customer.

The point of generic lists is to constrain them to certain types. You're trying to take a list that can have anything in it (Orders, Products, etc.) and squeeze it into a list that can only take Customers.

Rob Sobers
  • 20,737
  • 24
  • 82
  • 111
2

As others have pointed out, you cannot savely cast them, since a List<Object> isn't a List<Customer>. What you could do, is to define a view on the list that does in-place type checking. Using Google Collections that would be:

return Lists.transform(list, new Function<Object, Customer>() {
  public Customer apply(Object from) {
    if (from instanceof Customer) {
      return (Customer)from;
    }
    return null; // or throw an exception, or do something else that makes sense.
  }
});
nd.
  • 8,699
  • 2
  • 32
  • 42
2

You can create a new List and add the elements to it:

For example:

List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);
ayushgp
  • 4,891
  • 8
  • 40
  • 75
1

Your best bet is to create a new List<Customer>, iterate through the List<Object>, add each item to the new list, and return that.

Aric TenEyck
  • 8,002
  • 1
  • 34
  • 48
1

Similar with Bozho above. You can do some workaround here (although i myself don't like it) through this method :

public <T> List<T> convert(List list, T t){
    return list;
}

Yes. It will cast your list into your demanded generic type.

In the given case above, you can do some code like this :

    List<Object> list = getList();
    return convert(list, new Customer());
  • I like this solution. Even if you need to add SuppressWarnings, it is better to add it in one place than in every unsafe casting. – robson Nov 30 '19 at 22:55
1

Depending on what you want to do with the list, you may not even need to cast it to a List<Customer>. If you only want to add Customer objects to the list, you could declare it as follows:

...
List<Object> list = getList();
return (List<? super Customer>) list;

This is legal (well, not just legal, but correct - the list is of "some supertype to Customer"), and if you're going to be passing it into a method that will merely be adding objects to the list then the above generic bounds are sufficient for this.

On the other hand, if you want to retrieve objects from the list and have them strongly typed as Customers - then you're out of luck, and rightly so. Because the list is a List<Object> there's no guarantee that the contents are customers, so you'll have to provide your own casting on retrieval. (Or be really, absolutely, doubly sure that the list will only contain Customers and use a double-cast from one of the other answers, but do realise that you're completely circumventing the compile-time type-safety you get from generics in this case).

Broadly speaking it's always good to consider the broadest possible generic bounds that would be acceptable when writing a method, doubly so if it's going to be used as a library method. If you're only going to read from a list, use List<? extends T> instead of List<T>, for example - this gives your callers much more scope in the arguments they can pass in and means they are less likely to run into avoidable issues similar to the one you're having here.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
0

SIMPLEST SOLUTION IS TO USE

(((List<Object>)(List<?>) yourCustomClassList))
Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82
-1
List<Object[]> testNovedads = crudService.createNativeQuery(
            "SELECT ID_NOVEDAD_PK, OBSERVACIONES, ID_SOLICITUD_PAGO_FK FROM DBSEGUIMIENTO.SC_NOVEDADES WHERE ID_NOVEDAD_PK < 2000");

Convertir<TestNovedad> convertir = new Convertir<TestNovedad>();
Collection<TestNovedad> novedads = convertir.toList(testNovedads, TestNovedad.class);
for (TestNovedad testNovedad : novedads) {
    System.out.println(testNovedad.toString());
}

public Collection<T> toList(List<Object[]> objects, Class<T> type) {
    Gson gson = new Gson();
    JSONObject jsonObject = new JSONObject();
    Collection<T> collection = new ArrayList<>();
    Field[] fields = TestNovedad.class.getDeclaredFields();
    for (Object[] object : objects) {
        int pos = 0;
        for (Field field : fields) {
            jsonObject.put(field.getName(), object[pos++]);
        }
        collection.add(gson.fromJson(jsonObject.toString(), type));
    }
    return collection;
}
David Buck
  • 3,752
  • 35
  • 31
  • 35