简体   繁体   中英

Passing in an array for a generic type parameter

public class C<T>{

    private T a;

    public C(){

    }


}

In my Java textbook, it says the type parameter T can be any reference type, including an array type. I am trying to code an example to demonstrate this functionality (T being an array), but I do not know how. In my driver I do

C<int[]> o = new C<int[]>();

and it compiles but I do not know how to work with the T being int[] inside the C class definition. How would I make it, for example, create an array of 5 random integers and print them? Any meaningful demonstration of an array being subbed in for T will do actually.

The way you can achieve this is by declaring field a as T[] type inside the class C :

class C<T>{
    private T[] a;
    public C(T[] a){
        this.a = a;
    }
    public void set(int index, T value) {
        a[index] = value;
    }
}

Because your class's a member is private , you can't actually do anything with it. Typically, you access and modify a simple class's private members with getters and setters, respectively. Let's add a bit to your class:

public class C<T>{

    private T a;

    public C(){

    }

    public T getA() {
        return a;
    }

    public void setA(T a) {
        this.a = a;
    }
}

Now we have a generic getter/setter for our generic field.

In your driver, you can now do this:

C<int[]> o = new C<int[]>(); // create our generic object
int[] myA = new int[5];      // create an array of ints
o.setA(myA);                 // set the member in our object
// do whatever you want with myA

Now if other objects, methods, or classes handle o , they can all call o.getA to handle the same array. This is just one (contrived) example of how to work with generics.

Making a generic type an array type tends to be useful only for storing and retrieving them. This is because a generic type is meant to be worked with as if the type isn't known. I mean to say that if you make T an array type, like int[] , you can't work with T as if it were an array, because T could be of any type, not just an array.


Giving you a useful example is a lot more complicated. First thing that comes to mind is maybe some kind of table of rows:

public class GenericTable<T> {
    private T[] rows;

    public GenericTable(int numRows) {
        this.rows = new T[numRows];
    }

    public T getRow(int position) { 
        return rows[position];
    }

    public setRow(T row, int position) {
        this.rows[position] = row;
    }

    public void sortRows(Comparator<T> sortFunction) {
         Arrays.sort(rows, sortFunction);
    }

    public int size() {
        return rows.length;
    }
}

Above we have a generic class which does not have a getter/setter, but allows us to set rows and sort the data as we like.

In our driver, we can make a table of int arrays. This is a lot like a 2D array ( int[][] ), but our GenericTable abstracts one of the dimensions which is easier to read:

GenericTable<int[]> table = new GenericTable<>(5); // 5 rows of int[]s
for (int iRow = 0; iRow < table.size(); i++) {
    int length = /* a random int */;
    int[] myNums = new int[length];
    // insert a bunch of numbers into myNums
    table.setRow(myNums, iRow);
}

Now our table is filled, but let's say we want to sort the table based on the length of each row. Thanks to our generic definition of table sorting, this is as simple as:

table.sortRows(Comparator.comparing(int[]::length));

Now we might pass this table to another class, which does something else generically:

myTableDisplay.writeTable(table);

And maybe myTableDisplay.writeTable looks something like this:

public void writeTable(GenericTable<?> table) {
    // open a Object writer resource or something
    for (int iRow = 0; iRow < table.size(); iRow++) {
        Object row = table.getRow(iRow);
        // write the row with the resource
    }
}

Now writeTable doesn't need to know or care what kind of table is being written. This demonstrates the (admittedly limited) usability of T being an int[] , since only our driver cares that type T is int[] in this case, but no code anywhere else does.

You snippet is kinda describing the simplest of the containers, where there is only one element of arbitrary T . However since a is private is simply impossible for it to take any value apart from null unless you add a setter or make it non-private. So a set of close to minimal changes to make it a bit more worth it would be:

public class C<T> {

   private T a;

   public C() {};

   public T get() { return a; }

   public void set(T value) { a = value; }

}

Notice that generic containers lack the ability to instantiate a instance of T directly since their code cannot make assumptions about what T actually is. This true for C here as it is for any other containers in the standard Java library ( java.util.* ). So any value that the container may eventually contain must be created somewhere else and provided by the invoking code. In the example above, whatever is using the C typed instance would pass such an object using the setter:

class Blah {
  // ...
  void someMethod(...) {
      C<int[]> c = new C<int[]>();

      int[] fiveValues = new int[] {1, 2, 3, 4 ,5};

      c.set(FiveValues);
  } 
  // ...
}

You never will see something like new T() or new T[n] in the code of the container, it won't ever compile. The only way to create such instance within an invocation of a method in C is by delegating in some kind of factory object that is passed also either once at the construction of the C instance or passed as a parameter of whatever method is responsible to the creation.

And as for other task like compose a string representation it is possible to add a routine in C that enquires for the type of the T element class at run time and come out with an appropriate way to display it. How ever that would end up with if else if else if .... else statement that may break as the method has to support more unforeseen types. Normally it makes more sense to delegate that task also to the invoking class that is aware of the actual type T .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM