Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type casting an object to any Collection type

We recently faced a bug in our code which was basically related to OOPs concepts.

class ABC
{
    String a;
    ABC(){
        a = "abc";
    }
}

public class Main {


    static Object listABC() {
        List<ABC> listOfABC = new ArrayList<>();
        listOfABC.add(new ABC());
        return listOfABC;
    }

    public static void main(String[] args) throws java.lang.Exception {

        List<Long> listLong = (List) Main.listABC();
        System.out.println(listLong.get(0));
    }
}

Output: ABC@642c39d2

Shouldn't this raise a run time exception ? Can someone point me to the correct direction as to why doesn't this code raise an exception?

like image 709
Rachit Magon Avatar asked Sep 14 '16 05:09

Rachit Magon


People also ask

Which is used for casting of object to a type or a class?

Type Casting is a feature in Java using which the form or type of a variable or object is cast into some other kind of Object, and the process of conversion from one type to another is called Type Casting.

Can we cast any other type to Boolean data with type casting?

Casting between primitive types enables you to convert the value of one type to another primitive type. This most commonly occurs with the numeric types. But one primitive type can never be used in a cast. Boolean values must be either true or false and cannot be used in a casting operation.

Does type casting create a new object?

Casting does not create a new object (at least, not unless new conversion operators have been defined, which is uncommon in non-numeric types, and doesn't apply in your example). It merely instructs the compiler how to "treat" an object.

How do you cast a list of Supertypes to a list of subtypes?

Answering in 2022. Casting a List of supertypes to a List of subtypes is nonsensical and nobody should be attempting or even contemplating doing such a thing. If you think your code needs to do this, you need to rewrite your code so that it does not need to do this.


2 Answers

Generic types are erased, and in your example info about them no longer exists at runtime. They're only a compile time aid. Casting List<T> to List also discards info about the type at compile time, although it's still a valid cast.

So as long as you're doing legal casts at every step, which you are, it'll compile fine. At runtime the info about the type in the list is gone here.

If you tried to cast get(0) to a Long then youd get a classcastexception, since the item itself is an ABC.

like image 128
Jason C Avatar answered Sep 28 '22 08:09

Jason C


The answer is pretty simple. Generics are compile time components to ensure compile time compatibility. Generics are gone after compiling and hence don´t exist at Runtime anymore.

As Object listABC does return a List, (List) Test.listABC(); doesn´t throw an exception, because it´s valid as it actually returns a List.

you can assign it to List<Long> listLong because at runtime listLong doesn´t know about it´s Long generic anymore.

As a result this is, even though it looks wrong, valid executable code.

also the only reason this does work is that there is a PrintStream#println(Object) method, otherwise you´d get an Exception because your trying to call it with a wrong type as you can see in the following example.

static Object listABC() {
    List<Test> listOfABC = new ArrayList<>();
    listOfABC.add(new Test());
    return listOfABC;
}

public static void main(String[] args) throws java.lang.Exception {

    List<Long> listLong = (List) Test.listABC();
    System.out.println(listLong.get(0));
    test(listLong.get(0));
}

private static void test(Long longvalue) {
    System.out.println("TEST");
}

O/P

ABC@19e0bfd
Exception in thread "main" java.lang.ClassCastException: ABC cannot be cast to java.lang.Long
at ABC.main(ABC.java:19)
like image 44
SomeJavaGuy Avatar answered Sep 28 '22 08:09

SomeJavaGuy