Java 我可以对 Number 基类进行算术运算吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3873215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I do arithmetic operations on the Number baseclass?
提问by Tom Smith
I am trying to create a generic class in Java that will perform operations on numbers. In the following example, addition, as follows:
我正在尝试在 Java 中创建一个通用类,它将对数字执行操作。在下面的例子中,加法如下:
public class Example <T extends Number> {
public T add(T a, T b){
return a + b;
}
}
Forgive my naivety as I am relatively new to Java Generics. This code fails to compile with the error:
请原谅我的天真,因为我对 Java 泛型比较陌生。此代码无法编译并出现以下错误:
The operator + is undefined for the argument type(s) T, T
运算符 + 未定义参数类型 T, T
I thought that with the addition of "extends Number" the code would compile. Is it possible to do this Java or will I have to create overridden methods for each Number type?
我认为通过添加“扩展编号”,代码会编译。是否可以执行此 Java,或者我是否必须为每个 Number 类型创建覆盖方法?
回答by Nathan Feger
Number does not have a + operator associated with it, nor can it since there is no operator overloading.
Number 没有与之关联的 + 运算符,也不能,因为没有运算符重载。
It would be nice though.
不过会很好。
Basically, you are asking java to autobox a descedant of Number which happens to include Integer, Float and Double, that could be autoboxed and have a plus operator applied, however, there could be any number of other unknown descendants of Number that cannot be autoboxed, and this cannot be known until runtime. (Damn erasure)
基本上,您是在要求 java 自动装箱 Number 的后代,它恰好包括 Integer、Float 和 Double,可以自动装箱并应用加号运算符,但是,可能有任意数量的 Number 的其他未知后代无法自动装箱,这直到运行时才能知道。(该死的擦除)
回答by Tom Hawtin - tackline
Consider Example<Number>
, how would +
work on that? There is no add
or similar in Number
or even the likes of Integer
.
考虑一下Example<Number>
,如何+
解决这个问题?没有add
或类似的,Number
甚至类似的Integer
。
Worse consider final class FunkyNumber extends Number { ... weird stuff, no add op ... }
.
更糟糕的是考虑final class FunkyNumber extends Number { ... weird stuff, no add op ... }
。
回答by Andrei Fierbinteanu
There are similar questions to this one, and the answer is you can't do it like that.
这个问题也有类似的问题,答案是你不能那样做。
You could check if a and b are an instance of Long/Double/Integer/etc. and delegate the add to methods like:
您可以检查 a 和 b 是否是 Long/Double/Integer/etc 的实例。并将 add 委托给方法,例如:
public Integer add(Integer a, Integer b) {
return a+b; // this actually uses auto boxing and unboxing to int
}
And you would need to create one for every type that extends Number, so that's not really feasible. In other words, don't use generics for numeric operations. Number as a superclass is pretty limited.
并且您需要为扩展 Number 的每种类型创建一个,因此这实际上并不可行。换句话说,不要将泛型用于数字运算。作为超类的数量非常有限。
回答by leonbloy
Your problem is not really related to generics, rather to operators, primitives vs objects, and autoboxing.
您的问题实际上与泛型无关,而是与运算符、原语与对象以及自动装箱有关。
Think about this:
想一想:
public static void main(String[] args) {
Number a = new Integer(2);
Number b = new Integer(3);
Number c = a + b;
}
The above does not compile
以上不编译
public static void main(String[] args) {
Integer a = new Integer(2);
Integer b = new Integer(3);
Number c = a + b;
}
The above doescompile, but only because of autoboxing - which is kind of a hacky syntax glue introduced in Java 5, and only works (in compile time) with some concrete types : int-Integer for example.
上面确实可以编译,但只是因为自动装箱 - 这是 Java 5 中引入的一种黑客语法粘合剂,并且仅适用于(在编译时)某些具体类型:例如 int-Integer。
Behind the scenes, the Java compiler is rewriting the last statement ("I must unbox a
and b
to apply the sum operator with primitive datatypes, and box the result to assign it to object c
") thus:
在幕后,Java 编译器正在重写最后一条语句(“我必须取消装箱a
并b
使用原始数据类型应用 sum 运算符,并将结果装箱以将其分配给对象c
”),因此:
Number c = Integer.valueOf( a.intValue() + b.intValue() );
Java can't unbox a Number
because it does not know at compile time the concrete type and hence it cannot guess its primitive counterpart.
Java 无法对 a 进行拆箱,Number
因为它在编译时不知道具体类型,因此无法猜测其原始类型。
回答by Landei
Yes, Nathan is correct. If you want something like this, you have to write it yourself
是的,内森是对的。如果你想要这样的东西,你必须自己写
public class Example <T extends Number> {
private final Calculator<T> calc;
public Example(Calculator<T> calc) {
this.calc = calc;
}
public T add(T a, T b){
return calc.add(a,b);
}
}
public interface Calculator<T extends Number> {
public T add(T a, T b);
}
public class IntCalc implements Calculator<Integer> {
public final static IntCalc INSTANCE = new IntCalc();
private IntCalc(){}
public Integer add(Integer a, Integer b) { return a + b; }
}
...
Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE);
System.out.println(ex.add(12,13));
Too bad Java has no type classes (Haskell) or implicit objects (Scala), this task would be a perfect use case...
太糟糕了 Java 没有类型类(Haskell)或隐式对象(Scala),这个任务将是一个完美的用例......
回答by Stan Kurilin
You can do something like this
你可以做这样的事情
class Example <T extends Number> {
public Number add(T a, T b){
return new Double(a.doubleValue() + b.doubleValue());
}
}
回答by josefx
Even the java runtime library has this problem, most of the methods dealing with primitives have to duplicate the same functionality.
即使是 java 运行时库也有这个问题,大多数处理原语的方法都必须复制相同的功能。
The fastest option would be to write your code for one type and then copy it and replace the type to generate the methods for the other types. A short script should be enough to do this.
最快的选择是为一种类型编写代码,然后复制它并替换该类型以生成其他类型的方法。一个简短的脚本应该足以做到这一点。