Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics and numbers

Tags:

java

generics

In an attempt to see if I can clean up some of my math code, mostly matrix stuff, I am trying to use some Java Generics. I have the following method:

private <T> T[][] zeroMatrix(int row, int col) {
    T[][] retVal = (T[][])new Object[row][col];
    for(int i = row; i < row; i++) {
        for(int j = col; j < col; j++) {
            retVal[i][j] = 0;
        }
    }
    return retVal;
}

The line retVal[i][j] = 0 is the one causing me headaches. The goal of the line is to initialize the array with the T representation of 0. I've attempted to do all sorts of things with it: (T is defined in the class as T extends Number)

retVal[i][j] = (T)0;
retVal[i][j] = new T(0);

The only thing that works is

retVal[i][j] = (T)new Object(0);

Which is not what I want.

Is this possible? Is there an easier way to represent an NxM matrix of any type of Number(including potentially BigDecimal), or am I stuck?

like image 605
Scott Lemke Avatar asked May 18 '09 14:05

Scott Lemke


3 Answers

<T extends Number> T[][] zeroMatrix(Class<? extends Number> of, int row, int col) {
    T[][] matrix = (T[][]) java.lang.reflect.Array.newInstance(of, row, col);
    T zero = (T) of.getConstructor(String.class).newInstance("0");
    // not handling exception      

    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; 
            matrix[i][j] = zero;
        }
    }

    return matrix;
}

usage:

    BigInteger[][] bigIntegerMatrix = zeroMatrix(BigInteger.class, 3, 3);
    Integer[][] integerMatrix = zeroMatrix(Integer.class, 3, 3);
    Float[][] floatMatrix = zeroMatrix(Float.class, 3, 3);
    String[][] error = zeroMatrix(String.class, 3, 3); // <--- compile time error
    System.out.println(Arrays.deepToString(bigIntegerMatrix));
    System.out.println(Arrays.deepToString(integerMatrix));
    System.out.println(Arrays.deepToString(floatMatrix));

EDIT

a generic matrix:

public static <T> T[][] fillMatrix(Object fill, int row, int col) {
    T[][] matrix = (T[][]) Array.newInstance(fill.getClass(), row, col);

    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            matrix[i][j] = (T) fill;
        }
    }

    return matrix;
}    

Integer[][] zeroMatrix = fillMatrix(0, 3, 3); // a zero-filled 3x3 matrix
String[][] stringMatrix = fillMatrix("B", 2, 2); // a B-filled 2x2 matrix
like image 96
dfa Avatar answered Nov 16 '22 08:11

dfa


Arrays and Generics do not play well together:

"Arrays are covariant, which means that an array of supertype references is a supertype of an array of subtype references. That is, Object[] is a supertype of String[] and a string array can be accessed through a reference variable of type Object[] ."

see the Java Generics FAQ:

  • Can I create an array whose component type is a concrete parameterized type?
  • How do I generically create objects and arrays?
like image 44
bendin Avatar answered Nov 16 '22 09:11

bendin


it should be null instead of zero.

If you want to actually put in there the equivalent 0 for object T you will need to provide a factory of T. Something like this:

interface Factory<T> {
   T getZero();     
}

and you should make the method like this:

private <T> T[][] zeroMatrix(int row, int col, Factory<T> factory) {
    T[][] retVal = (T[][])new Object[row][col];
    for(int i = row; i < row; i++) {
        for(int j = col; j < col; j++) {
            retVal[i][j] = factory.getZero();
        }
    }

    return retVal;
}

You should also have proper implementations for the factory:

 class IntegerFactory implements Factory<Integer> {
    Integer getZero() {
       return new Integer(0);
    }
}

Normally you would put the getMatrix(int row, int column) in the factory implementation too in order to actually return a proper typed array.

like image 3
Mihai Toader Avatar answered Nov 16 '22 08:11

Mihai Toader