5

I'm trying to work with generics mostly for practice and for a little idea I had. At the moment I have a problem with: ClassCastException:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType. Most of the topics I found about this where from users that posted very specific code. This makes it really harder for me to understand. I tried to make the problem as simple as possible but still related to my actual problem. I hope someone can help.

The Bar class:

class Bar { }

The Foo class:

class Foo<T> {

  ArrayList<Object> list;

  Foo(int initialCapacity) {
    init(initialCapacity);
  }

  void init(int initialCapacity) {
    list = new ArrayList<Object>(initialCapacity);

    for (int i = 0; i < initialCapacity; i++) {
      try {
        list.add(((Class)((ParameterizedType)this.getClass().
          getGenericSuperclass()).getActualTypeArguments()[0]).newInstance());
      }
      catch (InstantiationException e) {

      }
      catch (IllegalAccessException e) {

      }
    }


  }

}

use:

Foo<Bar> com = new Foo<Bar>(100);
3
  • In what line is the error occurring? Commented Jul 18, 2014 at 15:53
  • list.add(((Class)((ParameterizedType)this.getClass(). getGenericSuperclass()).getActualTypeArguments()[0]).newInstance()); Commented Jul 18, 2014 at 15:58
  • And why are you casting the Type result from getGenericSuperclass to ParamererizedType? Commented Jul 18, 2014 at 16:01

5 Answers 5

4

You seem to be confused about Generics in Java.

Java does not implement Generics the same way it is done in, say, C# : you cannot retrieve type information of a generic type at runtime, because it's simply not saved after compilation (see: type erasure)

This means that if I declare a variable of type List<MyObject>, then I cannot know if it is a list of MyObject, because the type information is lost, and the class of this list is just List, which is not implementing ParameterizedType.

The only time where the generic type information is saved, is when it is known at compile time for a type definition:

public class MyList extends List<MyObject> {}

Here, MyList.class.getGenericSuperclass() should be implementing ParameterizedType. I'm afraid that what you are trying to do here is not possible, or at least, it could be working, if init was called on a class inheriting Foo, such as :

public class StringFoo extends Foo<String> {
    public StringFoo(int initialCapacity) { 
        super(initialCapacity); 
    }
}

StringFoo foo = new StringFoo(100);
Sign up to request clarification or add additional context in comments.

2 Comments

I don't think that last bit compiles. There is only a no-arg default constructor in te StringFoo class, since constructors aren't inherited. How can you pass a parameter?
@MDeSchaepmeester ah, indeed, I forgot to include the constructor -- fixing my answer.
2

The root of the error is that this in your example is an instance of Foo<String>, whose superclass is the non-parameterized type java.lang.Object. Thus getGenericSuperclass() is giving you Object.class instead of a ParameterizedType.

The pattern you're trying to use looks like the "type token" trick used by libraries such as gson where you define an anonymous subclass of the generic type at the point where you want to use it in order to capture the type parameters in the generic superclass signature. Your code would work if you did

Foo<Bar> com = new Foo<Bar>(100) {};

The empty braces make this an anonymous class whose generic superclass is the ParameterizedType representing Foo<Bar>.

Note that this trick can only work when you instantiate the type parameter with a non-parameterized class literal. If you had a method like

static <E> Foo<E> makeFoo(E element) {
  Foo<E> f = new Foo<E>(100) {};
  // do something with element
}

it would fail because ((ParameterizedType)this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0] would be a TypeVariable rather than a Class. Similarly

Foo<List<String>> listFoo = new Foo<List<String>>(5){}

would fail because here the first actual type argument is a ParameterizedType rather than a Class.

Comments

0

To answer your original question: you are trying to cast an object of the type Type to the type Class. Since Type is a supertype of Class this results in an exception - what a confusing sentence.

And here comes my second point: Do not use reflection unless you really really have to. It's the black magic of java! Also as Snaipe points out, and this is the most important thing, due to type erasure reflection will not help you with any problem related to generics.

1 Comment

actually, Type is an interface that Class implements, so this checks out (ParameterizedType is not, though)
0

What you're trying to do is only possible if you subclass Foo, providing an actual value for T that is captured in Foo's type definition:

class StringFoo extends Foo<String> {}

Then init should work as you expect. Without capturing an actual value for T in a type definition, there's no way to recover the value of T at runtime.

Comments

0

This is a solution

    public TO getTo() throws Exception{
      if (to == null) {
        try{
            to = ((Class<TO>)((ParameterizedType)this.getClass().
                       getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
        }catch(ClassCastException cce){
            cce.printStackTrace();
            to = ((Class<TO>)((ParameterizedType)(((Class<TO>)
                    this.getClass().getAnnotatedSuperclass().getType()).getGenericSuperclass()))
                        .getActualTypeArguments()[0]).newInstance();
        }   
      }
      return to;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.