tags:

views:

1361

answers:

4

This is what I'm trying to do:

import java.lang.reflect.*;

class exampleOuter <T extends Number>
{
    private exampleInner<T>[] elements;

    public exampleOuter(Class<T> type, int size)
    {
        elements = (exampleInner<T>[]) Array.newInstance(type, size);
    }
}

I was told that if I wanted to create generic arrays of type T, I should use

elements = (T[]) Array.newInstance(type,size);

So I tried to extend that to my custom class and got a ClassCastException (Ljava.lang.Double; cannot be cast to L*mypackagename*.exampleInner; I'm declaring the class in main like this:

exampleOuter<Double> test = new exampleOuter(Double.class,15);

I can declare the inner class just fine and I can also declare arrays that aren't generic of the innerClass, so I imagine it's something in the constructor of the outerClass. Any ideas?

EDIT: I understand what the problem is. When I create a new instance of the array, I create an array of doubles, not of exampleInner. I think. If that's right, I need to find a way to create an array of exampleInner while passing just Double.class to the function.

EDIT 2: I realize generic arrays are not typesafe, but I have to use them anyway because my teacher demands that we use them.

EDIT 3: I was told that to use generic arrays I had to allocate them that way, and to do so I need reflections, I think. The compiler tells me the class is using unsafe or unchecked operations, but I have to use generic arrays and that's the way I know to do it. If there's a better way I'll change the code.

A: 

You are creating, for some specific T, an object of type T[] and assigning it to a field of type exampleInner<T>[] which is going to be an error.

For T extends Number: the erase type of T[] is Number[]; for the erased type of exampleInner<T>[] is exampleInner[]. But the compiler warnings should have indicated that you were doing something wrong anyway.

But you almost certainly do not need reflection, so don't use it.

Tom Hawtin - tackline
A: 

T extends Number and you're trying to cast it to an exampleInner, which I doubt is in the right place in the Number hierarchy.

Try it without your exampleInner. Or try passing exampleInner as the type argument to the exampleOuter constructor.

Cogsy
+1  A: 

This is the solution I've come up with:

public exampleOuter(Class<T> type, int size)
{
    innerClass<T> aux = new innerClass<T>(); 
    elements = (exampleInner<T>[]) Array.newInstance(aux.getClass(), size);
}

I thought this would also work:

elements = (exampleInner<T>[]) Array.newInstance(innerClass<T>.class, size);

But it doesn't, probably because of the way generics are implemented in Java (type erasure and all that).

The problem with the first approach is that I'm forced to create a new object and instantiate despite not really needing it. Plus, it makes the code more bloated imo.

EDIT: The second approach wasn't working because I was using innerClass<T>.class instead of innerClass.class. Thanks for the suggestion, I'll use it now.

when you call aux.getClass(), the <T> part has already been erased. So you might as well just use innerClass.class
Cogsy
A: 

You don't have "generic array creation" here. The component type of the array is "exampleInner" (well, it should be exampleInner, but array component types must be "reified types", so it can't store the at runtime.), which is known at compile time. So you don't need to pass in the Double.class parameter.

What you really need to do is create an array of a parameterized type. One way to do this is to create an array of the raw type, and cast it to the array-of-parameterized type. This will allow you to use the array as you normally would and get the benefits of the generics of not having to cast when you get stuff out and stuff.

Technically, this is an unchecked cast, because it could in theory cause unexpected problems later because it can't prevent you from putting the wrong type of objects in the array. But since this is a private variable in your class, and I'm assuming that you only manipulate it within your class, and if you trust your own code to use it correctly, then it will work.

import java.lang.reflect.*;

class exampleOuter <T extends Number>
{
    private exampleInner<T>[] elements;

    @SuppressWarnings("unchecked")
    public exampleOuter(int size)
    {
        elements = (exampleInner<T>[]) new exampleInner[size];
    }
}
newacct