Frame91
Frame91

Reputation: 3789

Generics and ClassCastException

Given the following piece of code:

public class ClassCastTest {

    private static class GenericHolder<T> {
        private T object;

        public GenericHolder(Object object) {
            this.object = (T) object;
            System.out.println(getObject());
        }

        public T getObject() {
            return object;
        }
    }

    public static void main(String[] args) {
        GenericHolder<String> foo = new GenericHolder<>(3l);
        System.out.println(foo.getObject());
    }

}

Why does Java throw a ClassCastException in the second line of the main-method instead of the second line of the GenericHolder?

Upvotes: 3

Views: 540

Answers (2)

Paul Boddington
Paul Boddington

Reputation: 37645

In addition to Louis' answer, it's useful to point out that casting to a T by writing (T) does "do something" in the case that T is bounded. For example, if you write

private static class GenericHolder<T extends CharSequence>

instead, then the line

this.object = (T) object;

does throw a ClassCastException, because you can't cast a Long to a CharSequence (note the question says 3l not 31). However it won't attempt to cast to a String at that point because the type T is not known at runtime.

Upvotes: 2

Louis Wasserman
Louis Wasserman

Reputation: 198024

Because of the way generics are implemented in the language, your cast to (T) doesn't actually do anything. It's only when you use a generic type in a way that actually gets out a concrete type -- here, System.out.println expects a String and it does the cast to get it -- that the runtime actually does any casting.

As far as the Java runtime is concerned, there's no difference between a GenericHolder<String> and a GenericHolder<Integer>; they both hold an Object. Java just inserts casts anywhere you get a concrete type out of a generic type.

Research type erasure for more details.

Upvotes: 6

Related Questions