avisnacks
avisnacks

Reputation: 81

Returning an Array from a generic class

I get a ClassCastException error when I run this because of the implicit cast of d to a double when I run the code. However, if I change reference to d in to Object[] then it can't be a parameter to the set function. If I change the set function to accept an Object[] then everything works fine, but then the class will fail at runtime if anyone calls set on an object that isn't of type N.

I need a solution that can get() the old array (or a clone thereof) and that can set() data to a new array.

public class Foo<N> {

    public static void main(String[] args) {
        Foo<Double> foo = new Foo<Double>();
        Double[] d = foo.get();

        // do stuff to d ...

        foo.set(d);
    }

    N[] data;

    public Foo() {
        data = (N[]) new Object[2];
    }

    public N[] get() {
        return (N[]) data;
    }

    public void set(N[] data) {
        this.data = data;
    }

}

Upvotes: 7

Views: 160

Answers (4)

Lii
Lii

Reputation: 12112

To create an array with the right runtime type requires some kind of runtime representation of that type. A generic class like Foo<N> has no runtime representation of N.

There are two solutions:

  1. Use a List<N> instead. This is best if it is possible!
  2. Manually add a runtime representation of N by passing in a Class<N> to Foo, use java.lang.reflect.Array.newInstance to create the array.

Code for the second solution:

public Foo(Class<N> newDataClass) {
    data = (N[]) Array.newInstance(newDataClass, 2);
}

Foo<Double> foo = new Foo<>(Double.class);

EDIT:

If what you want to do is instead to get a copy of an existing Double array you can do that with (N[]) data.clone(). Setting it will not be a problem.

Upvotes: 1

qwertz
qwertz

Reputation: 14792

The problem with a generic is, that it does not have any specific type at runtime. It's just the class Object, which means, that creating such object is completely pointless, because you would, in fact, just create an object of type Object.

You can however create such objects from outside of the class, because the real type of the object is known here (Double). Thus I would suggest to use some sort of List, which can be dynamic, to store the values.

Upvotes: 0

yiannis
yiannis

Reputation: 1441

A convenient (but verbose) way to do this would be to change the constructor to take a dummy argument with the array type, since you know that it is double at your main method.

  public class Foo<N> {
         N[] data;

         public Foo(N inType) {
             data = (N[]) Array.newInstance(inType.getClass(), 2) ;
         }

         public N[] get() {
             return (N[]) data;
         }

         public void set(N[] data) {
             this.data = data;
         }

         public static void main(String[] args) {
             Foo<Double> foo = new Foo<Double>(new Double(0));
             Double[] d = foo.get();
             // do stuff to d ...
             foo.set(d);
         }

  }

Upvotes: 1

OldCurmudgeon
OldCurmudgeon

Reputation: 65813

There's a trick to this.

class Foo<N> {

    // Deliberately no parameters.
    N[] myArray = makeArray();

    private N[] makeArray(N... ns) {
        return ns;
    }

    public N[] get() {
        return myArray;
    }
}

This may look like there is no casting (which is a good thing) but actually there is, it is just being done by the varargs system.

Upvotes: 1

Related Questions