pf_miles
pf_miles

Reputation: 927

How to implement a function to convert a generic typed array to a generic typed 2-dimensional array in java?

public static <T> T[][] toTwoDim(T[] array)

The function signature as it is above.. It's a generic typed function, which can be used no matter what type is the data contained in the array. generally, it receives an array, and return a 2-dimensional array with its half elements in the first row, and the other half in the second row. I 've no idea how to implement it cause I could not create a generic typed 2-dimensional array inside the function. Some one help me out? Thanks!

Upvotes: 0

Views: 166

Answers (4)

gdejohn
gdejohn

Reputation: 7579

You could do this, which doesn't require suppressing any warnings.

public static <T> T[][] toTwoDim(Class<T[][]> clazz, T[] array)  
{  
   int halfLength = array.length / 2;  
   T[][] ret = clazz.cast(Array.newInstance(clazz.getComponentType().getComponentType(), 2, halfLength + 1));  
   System.arraycopy(array, 0, ret[0], 0, halfLength);  
   System.arraycopy(array, halfLength, ret[1], 0, array.length - halfLength);  
   return ret;  
}

Upvotes: 0

pf_miles
pf_miles

Reputation: 927

I found the perfect solution:

@SuppressWarnings("unchecked")
public static <T> T[][] toTwoDim(T[] array) {
    Class<T> ctype = (Class<T>) array.getClass().getComponentType();
    int halfLength = array.length / 2;
    T[][] ret = (T[][]) Array.newInstance(ctype, 2, 1);
    T[] r1 = (T[]) Array.newInstance(ctype, halfLength);
    T[] r2 = (T[]) Array.newInstance(ctype, array.length - halfLength);
    ret[0] = r1;
    ret[1] = r2;
    for (int i = 0; i < halfLength; i++)
        r1[i] = array[i];
    for (int i = 0; i < array.length - halfLength; i++) {
        r2[i] = array[i + halfLength];
    }
    return ret;
}

public static void main(String[] a) {
    Integer[] bar = { 1, 2, 3, 4, 5 };
    Integer[][] dims = toTwoDim(bar);
    for (Integer[] r : dims) {
        for (Integer d : r) {
            System.out.print(d + " ");
        }
        System.out.println();
    }
}

output:
1 2
3 4 5

the generic type of the 'toTwoDim' function is erased, but the incoming array's element type could be obtained via reflection!

Upvotes: 1

Stephen C
Stephen C

Reputation: 718788

It should be possible to do.

The basic approach is to use java.lang.reflect.Array.newInstance(clazz, dimX, dimY) to create the array instance.

  • If you want the result array's base type to be the same as the base type of the argument, then use reflection to get the base type from array.getClass().

  • If you want the result array's base type to be <T>, then you will need to add an extra argument to toTwoDim whose type is Class<T>, and use it to pass the class object for the desired array base type. (Type erasure means that it is not possible for the toTwoDim method to determine the class object for <T> at runtime. Passing the class object as an argument is the standard workaround.)

Upvotes: 1

Mark Elliot
Mark Elliot

Reputation: 77044

I played around with this for quite a bit, and my understanding, for reasons of type erasure, is that this isn't something that's possible.

Based on other examples of how to create arrays of generic type parameters it seems like something like the following code should work, but ultimately it fails only at the return of the function where the Object[][] cannot be cast to an Integer[][]. It would fail earlier except that IIRC the initial cast of (T[][]) is basically removed at compile time and acts to prevent a warning, thus it has no real impact.

@SuppressWarnings("unchecked")
public static <T> T[][] toTwoDim(T[] array){
    int halflen = array.length / 2;

    T[][] foo = (T[][]) new Object[2][];

    foo[0] = (T[]) new Object[halflen];
    foo[1] = (T[]) new Object[halflen];

    for(int i = 0; i < halflen; i++){
        foo[0][i] = array[i];
        foo[1][i] = array[i+halflen];
    }

    System.out.println(Arrays.asList(foo[0]));
    System.out.println(Arrays.asList(foo[1]));

    return foo;
}

public static void main(String[] a){
    Integer[] bar = {1,2,3,4};
    Integer[][] foo = toTwoDim(bar);
    System.out.println(Arrays.asList(foo[0]));
}

Upvotes: 1

Related Questions