Java generics and the Number class

妖精的绣舞 提交于 2019-12-01 00:13:43

问题


I want to create a method that compares a number but can have an input that is any of the subclasses of Number.

I have looked at doing this in the following manner...

public static <T extends Number> void evaluate(T inputNumber) {
  if (inputNumber >= x) {
    ...
  }
}

I need to get the actual primative before I can perform the comparison, the Number class has methods to retrieve this for each primative but I want a clean way of selecting the correct one.

Is this possible?

Cheers


回答1:


Unfortunately there is no way to get the primitive type from the wrapper type without resorting to if/else blocks.

The problem is that it just wouldn't be possible to implement such a method in a generic way. Here are some seemingly possible approaches which one could expect to find in the Number class:

public abstract X getPrimitiveValue();

This would be nice, wouldn't it? But it's impossible. There is no possible X that could be an abstraction over int, float, double etc.

public abstract Class<?> getCorrespondingPrimitiveClass();

This won't help either, because there is no way to instantiate primitive classes.

So the only thing you can do that is common to all types is to use the longValue() or doubleValue() methods, but either way you are losing information if you're dealing with the wrong type.

So no: the java number hierarchy is just not suited to solve such problems in a generic way.




回答2:


The Number API doesn't offer a clean way to get the value; you have have to use instanceof.

One solution is to "fold" the values into two types: long and double. That way, you can use this code:

if( inputNumber instanceof Float || inputNumber instanceof Double ) {
    double val = inputNumber.doubleValue();
    ...
} else {
    long val = inputNumber.longValue();
    ...
}

Note that this only works for the standard number types but Number is also implemented by a lot of other types (AtomicInteger, BigDecimal).

If you want to support all types, a trick is to use BigDecimal:

BigDecimal value = new BigDecimal( inputNumber.toString() );

That should always work and give you the most exact result.




回答3:


Methods with <T extends Number> are always trouble, since you can't really do anything on a Number (all the operators are defined for the children). You would need to either do a ton of instanceof for each child of Number and treat that case by casting to the subtype. Or (better I think - that's the way Sun does it) is to just have a method for each child type, possibly taking advantage of boxing/unboxing for operators like +,-,> etc. where that is possible (all wrappers, not for BigInteger/BigDecimal or any custom types).




回答4:


If it's really just about comparing the argument to another value of the same type parameter then you could do the following (just adding in T x for simplicity)

   public static <T extends Number & Comparable<? super Number>> int evaluate(T inputNumber, T x) {
          if (inputNumber.compareTo(x) > 0) { ... }
   }



回答5:


in this case you can use an ordinary method without generics



来源:https://stackoverflow.com/questions/3923081/java-generics-and-the-number-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!