4

I have generic type with Class<T> object provided in constructor. I want to create two-dimensional array T[][] in this constructor, is this however possible?

Jason C
  • 34,234
  • 12
  • 103
  • 151
Krzysztof Stanisławek
  • 1,197
  • 4
  • 12
  • 26
  • Not in Java, only in languages with runtime generics like C#. Think about erasure. – Benjamin Gruenbaum Aug 07 '13 at 18:28
  • Please post the specific signature of the constructor you're thinking of using. This may be possible, but it's not clear what you're asking. – chrylis -cautiouslyoptimistic- Aug 07 '13 at 18:30
  • 1
    Yes, you can use Array.newInstance(). See http://stackoverflow.com/questions/529085/java-how-to-generic-array-creation. I'd flag as a duplicate but I'm out of flags, can somebody take care of this? – Jason C Aug 07 '13 at 18:31
  • @JasonC Are you out of close votes too? – arshajii Aug 07 '13 at 18:33
  • @arshajii I don't think I have enough reputation to cast close votes. I can only share / edit / flag. – Jason C Aug 07 '13 at 18:37
  • 1
    @JasonC It's not exactly a duplicate, because this is asking about two-dimensional arrays and the question you linked doesn't seem to have any talk about creating multidimensional instances, which could lead someone to think it only works for one dimension and thus a more complicated procedure would be required than actually is. – JAB Aug 07 '13 at 18:40
  • @JAB 1) See my answer below, 2) You would *hope* (key word) that somebody would check the documentation for Array.newInstance and notice the dimension parameters, and 3) As for flagging for duplicate... good point, I agree(-ish). – Jason C Aug 07 '13 at 18:41
  • @JAB After reading SilverHaze's answer below, yes, agreed. – Jason C Aug 07 '13 at 18:49
  • 1
    It was closed as a duplicate, although I disagree now based on @JAB's comments above. Some of the other answers previously posted here (now deleted) demonstrated a lack of understanding that the 1D case described in the linked question could be extended to 2D - precisely the situation JAB described above. I've attempted to show that in my answer. I actually feel this question should be reopened and the other one be marked as a duplicate of *this* one, since this is a more general case. – Jason C Aug 09 '13 at 16:57

2 Answers2

16

Same as How to create a generic array in Java? but extended to 2D:

import java.lang.reflect.Array;

public class Example <T> {

    private final Class<? extends T> cls;

    public Example (Class<? extends T> cls) {
        this.cls = cls;
    }

    public void arrayExample () {
        // a [10][20] array
        @SuppressWarnings("unchecked")
        T[][] array = (T[][])Array.newInstance(cls, 10, 20);
        System.out.println(array.length + " " + array[0].length + " " + array.getClass());
    }

    public static final void main (String[] args) {
        new Example<Integer>(Integer.class).arrayExample();
    }

}

Note after reading JAB's comment above: To extend to more dimensions, just add []'s and dimension parameters to newInstance() (cls is a Class, d1 through d5 are integers):

T[] array = (T[])Array.newInstance(cls, d1);
T[][] array = (T[][])Array.newInstance(cls, d1, d2);
T[][][] array = (T[][][])Array.newInstance(cls, d1, d2, d3);
T[][][][] array = (T[][][][])Array.newInstance(cls, d1, d2, d3, d4);
T[][][][][] array = (T[][][][][])Array.newInstance(cls, d1, d2, d3, d4, d5);

See Array.newInstance() for details.

Community
  • 1
  • 1
Jason C
  • 34,234
  • 12
  • 103
  • 151
  • I noticed the OP edited the question and added "in this constructor". Same method as above (e.g. move the code from arrayExample() into the constructor). – Jason C Aug 07 '13 at 18:59
  • Thank you, I didn't know (and I thought that I checked in documentation) that I can use newInstance with more parameters - my fault, I could check this out. – Krzysztof Stanisławek Aug 07 '13 at 19:33
  • 1
    It is not safe to cast to `T[][]` (or whatever). `cls` may be a primitive type. – newacct Aug 08 '13 at 23:23
  • @newacct +1 but I'm out of votes. You would have to do something like `new Example(int.class)` to get to that point, which is arguably weird, but yes, you are right. I'll update when I get a chance. – Jason C Aug 08 '13 at 23:42
  • @newacct There's no a good way to handle that situation. I could check if `cls == int.class` in `arrayExample()` and add a special case, and do the same for other primitive types, but of course that ends up being a maintenance nightmare with a bunch of duplicate code. It boils down to not being able to cast to generic primitive types. So while the example does fail if `cls` is a primitive type's class, I don't think it's a situation that is worth taking care of (opinion) -- the way around it would be to use the object types instead of the primitives. – Jason C Aug 09 '13 at 03:52
  • 1
    @JasonC: well, you could just return `Object` instead of a particular type of array. Or at least, the last level of the multidimensional array must be replaced with `Object`. (So, a two-dimensional array can be safely represented by `Object[]`; a one-dimensional array can only be represented by `Object`.) – newacct Aug 10 '13 at 08:00
2

You have to use reflection, but it's possible: http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Array.html#newInstance%28java.lang.Class,%20int...%29

Creates a new array with the specified component type and dimensions.

JAB
  • 19,150
  • 4
  • 64
  • 78