0

I have a byte array like this, that I do some operations on like increment and decrement.

byte[] cells = new byte[numCells]
....
....
cells[index]++;

Now, I want to change the type of the array cells based on some user input parameter to byte, short, int or long.

So, I made a new class Cell

public class Cell<T extends Number> {

    T cell;

    Cell(T defaultValue){

        cell = defaultValue;
    }

    T get(){
        return cell;
    }

    void set(T t){
        cell = t;
    }
}

And I am trying to use it like this

ArrayList<Cell<?>> cells;

if(cellSize == 8)
    cells = new ArrayList<Cell<Byte>>(numCells);
else if(cellSize == 16)
    cells = new ArrayList<Cell<Short>>(numCells);
...
...

The compiler throws the following error

error: incompatible types: ArrayList<Cell<Byte>> cannot be converted to ArrayList<Cell<?>>
cells = new ArrayList<Cell<Byte>>(numCells);
        ^

How can I accomplish this?

  • note that using a parameter to decide at runtime what array to instantiate, makes the generics here a bit useless... I wonder if the parameter itself (8, 16, 32, etc) can be used to instantiate the correct array without an "if" statement... if there is no way, I would try a factory pattern based on a map where the key is your type size (8, 16, etc) and the value is the type of the array. – Pam Stums Aug 04 '22 at 19:58

3 Answers3

0

You have to obey the covariance/contravariance rules of the language.

ArrayList<Cell<Byte>>
// is not assignable to
ArrayList<Cell<?>>

but:

ArrayList<Cell<Byte>>
// is not assignable to
ArrayList<? extends Cell<?>>
  • Well having said that. add()-ing and get()-ing from this type isn't possible without casting it back to something without a wildcard ... But thats correct, since you specified that the element of the array is at least Cell> but you dont' know the actual type. so you cannot just add a new Cell() – StefTheDrummer Aug 04 '22 at 19:27
  • I would explain it this way: when instantiating an array with a specific type, i.e. new Array>(), we allow to add only Cell elements. Hence, we don't allow to add Cell elements or any other types. But Array> is "broader" and may accept other types than Cell elements. That's why it is not possible. – Pam Stums Aug 04 '22 at 20:19
  • Since you're trying to instantiate different types of arrays, I would in this case use a "raw" list type which can accept any type of list. simply use: List myList; without any generics. – Pam Stums Aug 04 '22 at 20:28
0

You don't need to decide for your generics on creation time:

List<Cell<?>> cells = new ArrayList<>(10);

cells.add(new Cell(Short.MAX_VALUE));
cells.add(new Cell(Byte.MAX_VALUE));
asbachb
  • 543
  • 3
  • 17
0

You'd have to type the variable as ArrayList<? extends Cell<?>>.

But even if that gets it to compile, it might not help you much. Wildcards are useful as method parameters, otherwise they're mostly a hindrance.

You might want to redesign your code so that the class is used in another class which has a type variable shared with Cell<T>, such as Table<T> so you just work with T inside both classes, and use the actual type in your "main" code when instantiating a Table<Short> for example.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • But I would then have the same problem with Table class right? – Sandeep Tadepalli Aug 05 '22 at 01:41
  • @SandeepTadepalli only if your Table can contain different kinds of cells. If that's the case you'll have to rethink your design since generics won't help you no matter what. – Kayaman Aug 05 '22 at 06:03