5

I want to write a generic method in java like below:

public <T extends Number & Comparable<T>> void test(T[] a){
    T b=a[0];
    if(a[0]>0){
        a[0]*=a[0];
        b+=a[1];
    }
}

Then later, I can supply either Integer[] or Double[] or other Number subtypes to the method. But the code I tried above gives me errors.

Please help me. Thank you.

Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
  • What is the problem you are trying to solve? Java doesn't support this kind of generic operation. If we understood the use case, perhaps we could suggest alternative options. For example, I find it's never a good idea to use arrays of wrapper classes (like `Integer[]`) instead of arrays of primitives (like `int[]`). Is there a reason you need `Integer` or `Double` instead of `int` or `double`? – Daniel Pryden Dec 20 '11 at 20:44
  • @DanielPryden: I am trying to solve: write a method which accept int[], float[], or double[] and inside which I need to do some comparison and arithmetic, then return the same type of array int[], or float[], or double[]. –  Dec 20 '11 at 20:55
  • Then the best you can do is to factor out your actual calculations into a method that operates on a `double[]` and returns a `double[]` (since `double` is wider than both `int` and `float`). You will still need to have two additional methods to support `int[]` and `float[]` arguments. – Daniel Pryden Dec 21 '11 at 00:40

3 Answers3

5

all types (including the inferred generic types) except the primitives are Objects which don't support the arithmetic operations (the wrapper classes use boxing/unboxing to get the known psuedo behavior)

and type erasure makes the compiled code use casts to get the proper behavior (i.e. at runtime the JVM doesn't know what type was passed in which it would need to know to get the proper boxing/unboxing behavior)

the only (real) solution is to provide implementations for all primitives you want to support

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • thank you for the answer. Is there any shorter, more elegant way of doing this other other replicating code? –  Dec 20 '11 at 20:38
  • @littleEinstein: If you just want to do comparisons, you can use the [`compareTo()` method of `Comparable`](http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html#compareTo(T)). But you can't perform arithmetic on `Number` instances in Java. – Daniel Pryden Dec 20 '11 at 20:40
  • @DanielPryden: right. But doing arithmetic is a must for my method. Do you have a good solution in this case without writing repetitive code? –  Dec 20 '11 at 20:42
  • @littleEinstein: As I wrote in my comment on your question, what we need is an explanation of your use case. *Why* are you doing it this way? Could you just upcast everything to, say, `double`, and use that? (`double` can hold all the values of any other numeric type except `long` without losing precision.) – Daniel Pryden Dec 20 '11 at 20:47
3

You can't do this in Java with generics. That's a benefit of C++ for example.

In some way you can define this as "strange", because it is possible to use operators on Java's primitive wrappers. But that is because you can't use operators on java.lang.Number, the superclass of the primitive wrappers.

Some resources:

Community
  • 1
  • 1
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • OK, now I understand the reason. But how to actually reuse the code if I want my method to be able to work for Integer[], Double[], Float[]? –  Dec 20 '11 at 20:39
  • 1
    That's the annoying part of Java Generics: You simply can't. The only thing you might try is to always use double and convert the data before and after usage to and from double. – Martijn Courteaux Dec 20 '11 at 20:41
1

You've got Comparable, so if we has a zero, a[0]>0 could be replaced by a[0].compareTo(zero) > 0 (no, I think it's < 0, I can never remember). But now we've run out of useful stuff from Double and the like.

If Double and friends weren't java.lang.Comparable we could supply our own java.util.Comparator. That is we take the implementation of comparison outside of the data object. We can also do that addition and multiplication.

public interface Testor<T> { // Choose a better name...
    boolean isStriclyPositive(T value);
    T add(T lhs, T rhs);
    T square(T value);
}

static final Testor<Integer> INTEGER_TESTOR = new Testor<>() { // Java SE 7 diamond.
    public boolean isStriclyPositive(Integer value) { return value > 0; }
    public Integer add(Integer lhs, Integer rhs) { return lhs + rhs; }
    public Integer square(Integer value) { return value*value; }
}
// ... same for Double, etc.; can't use an enum :( ...

test(new Integer[] { 42, 1972, 86 }, INTEGER_TESTOR);

public <T> void test(T[] a, Testor<T> testor) {
    T b = a[0];
    if (testor.isStrictlyPositive(a[0])) {
        a[0] = testor.square(a[0]);
        b = testor.add(b, a[1]);
    }
}

Note for things like Short, summing two of them will give you an int.

(Usual Stack Overflow disclaimer: not so much as attempted to compile the code.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305