3

I have a class Test and a method testMethod. I try to pass an int and an array of type T to the method, and it should return the int'th element of the array.

public class Test  {
    public static void main(String[] args)  {
        System.out.println(testMethod(1, new int[] {1,2,4}));
    }

    public static <T> T testMethod(int rank, T[] elements)  {
        return elements[rank];
    }
}

However I get a _method testMethodin class Test cannot be applied to given types_, T extends Object declared in method <T>testMethod(int,T[]).

I guess the issue is that the array is of basic type int. I tried changing it to Integer and it worked.

Is there a way to make it work, while still using basic numeric types like int or double or float?

2
  • This is because you are using int[]. Try it with Integer[]. System.out.println(testMethod(1, new Integer[] {1,2,4}));. Commented Feb 7, 2018 at 9:29
  • 1
    You could check Why don't Java Generics support primitive types?, not really a duplicate but this is really the same idea Commented Feb 7, 2018 at 10:03

4 Answers 4

4

You have to overload the testMethod(int, T[]) method to pass an int[] array:

public static int testMethod(int rank, int[] elements) {
    return elements[rank];
}

Otherwise, you need to meet requirements of T[], T extends Object (which denies primitive types) and pass an Integer[] array:

public static <T> T testMethod(int rank, T[] elements)  {
    return elements[rank];
}

Now you can pass either int[] or Integer[]:

final Integer i1 = testMethod(1, new Integer[]{1, 2, 4});
final int i2 = testMethod(1, new int[]{1, 2, 4});

Is there a way to make it work, while still using basic numeric types like int or double or float?

Unfortunately, only by method overloading. Have a look at the Arrays.binarySearch methods (18 different signatures in there). Most of the signatures were designed only to cover all the types.

Would overloading require just copying the code from the main function though?

I am afraid, yes (with small type and naming changes). Find the difference :)

public static void parallelSort(long[] a, int fromIndex, int toIndex) {
    rangeCheck(a.length, fromIndex, toIndex);
    int n = toIndex - fromIndex, p, g;
    if (n <= MIN_ARRAY_SORT_GRAN ||
        (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
    else
        new ArraysParallelSortHelpers.FJLong.Sorter
            (null, a, new long[n], fromIndex, n, 0,
             ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
             MIN_ARRAY_SORT_GRAN : g).invoke();
}

public static void parallelSort(float[] a, int fromIndex, int toIndex) {
    rangeCheck(a.length, fromIndex, toIndex);
    int n = toIndex - fromIndex, p, g;
    if (n <= MIN_ARRAY_SORT_GRAN ||
        (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);  // 1
    else
        new ArraysParallelSortHelpers.FJFloat.Sorter                     // 2
            (null, a, new float[n], fromIndex, n, 0,                     // 3
             ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
             MIN_ARRAY_SORT_GRAN : g).invoke();
}

Is it a good practice to copy paste with little changes such code into several functions?

It is definitely not. But do we have another way?

You could say that primitive boxing might be an option:

final int[] ints = {1, 2, 4};
final Integer i3 = testMethod(1, Arrays.stream(ints).boxed().toArray(Integer[]::new));

But does a good API force users to convert their data to fit the given signatures?

Sign up to request clarification or add additional context in comments.

3 Comments

Hm, thanks, that's a good idea. I knew of overloading, but combination of overloading and generics might work even better, don't you think? After all I only need to overload for the several basic numeric types and the generic will make sure the rest is covered as well.
Would overloading require just copying the code from the main function though? Is it a good practice to copy paste with little changes such code into several functions?
Thank you for detailed answer!
1

You cannot use a primitive type in place of a generic type parameter.

You can pass an Integer array instead:

System.out.println(testMethod(1, new Integer[] {1,2,4}));

Comments

1

You can't use a primitive in a Generic type because this is not inheriting Object. See more about that in Why don't Java Generics support primitive types? . For the conversion into an Integer array in your case, you can use the Streamn API do the boxing :

public static Integer[] boxed(int[] array){
    return IntStream.of(array).boxed().toArray(Integer[]::new);
}

It is basicily the same as iterating the array and boxing the value... into another instance.

You need to do that each time you want to use a primitive array in a generic method... not perfect but this will allow you to convert every existing array without the need to changing the type of an existing variable (Integer can be null which add other problems).

int[] array = {1,2,4};
System.out.println(testMethod(1, boxed(array)));

EDIT:

Without having to change your calls, simply by overriding the method for the primitve int :

public static int testMethod(int rank, int[] array){
    return testMethod(rank, Arrays.stream(array).boxed().toArray(Integer[]::new));
}

public static long testMethod(int rank, long[] array){
    return testMethod(rank, Arrays.stream(array).boxed().toArray(Long[]::new));
}

public static double testMethod(int rank, double[] array){
    return testMethod(rank, Arrays.stream(array).boxed().toArray(Double[]::new));
}

NOTE: for some type, you will probably be forced to simply build the array with a loop ... this will be a bit more verbose.

3 Comments

good point, +1, but now we're going to write n versions of the boxed method, aren't we? Instead of just consuming the API, we are building a lot of bridges first :)
I agree @AndrewTobilko, but reusing your example, Arrays.binarySearch as a lot of overloads ;) note that my example is not the design I would use for the overloads, this was just an example. Overloading testMethod for primitives would be my choice. No bridge needed in that case.
Note @AndrewTobilko that the bridge could be acceptable if we have more than one method to overload. Instead of overloading 10methods for each type, we provided the solution to convert the array.
0

I think you already mentioned the solution to make this code work in your question.. the only we is that we have to use Integer instead of int..

public static void main(String[] args)  {
    System.out.println(testMethod(1, new Integer[] {1,2,4}));
}

public static <T> T testMethod(int rank, T[] elements)  {
    return elements[rank];
}

If you want to use int, you cannot use T[] and would have to use int[] instead..

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.