所以我读了discussion about Numbers here,因为我有类似的问题。 就我而言,我希望能够对Numbers进行数学运算。我的想法是编写一个不可变的'RealNumber'类来处理原始的数字(整数,长整数,浮点数和双精度数),而不需要一堆实例控件。有人提到过载方法,让编译器完成工作 这是我的第一次尝试:
简单的TestClass:
public class Test {
public static void main(String[] args) {
RealNumber<Double> d = RealNumber.create(3.4);
d.add(4.7);
}
}
RealNumber类:(请在评论中提及方法)
public class RealNumber<N extends Number> extends Number{
N number;
private RealNumber(N number){
if (number == null){
throw new NullPointerException("number is null");
}
this.number = number;
}
public N get(){
return number;
}
//note this Method
public RealNumber<N> add(N number){
return add(number);
}
private RealNumber<Integer> add(Integer number){
return new RealNumber<Integer>(intValue() + number);
}
private RealNumber<Long> add(Long number){
return new RealNumber<Long>(longValue() + number);
}
private RealNumber<Float> add(Float number){
return new RealNumber<Float>(floatValue() + number);
}
private RealNumber<Double> add(Double number){
return new RealNumber<Double>(doubleValue() + number);
}
@Override
public int intValue() {
return number.intValue();
}
@Override
public long longValue() {
return number.longValue();
}
@Override
public float floatValue() {
return number.floatValue();
}
@Override
public double doubleValue() {
return number.doubleValue();
}
public static final RealNumber<Integer> create(Integer number){
return new RealNumber<Integer>(number);
}
public static final RealNumber<Long> create(Long number){
return new RealNumber<Long>(number);
}
public static final RealNumber<Float> create(Float number){
return new RealNumber<Float>(number);
}
public static final RealNumber<Double> create(Double number){
return new RealNumber<Double>(number);
}
}
所以第一个测试引导我进入StackOverflowError,因为方法'add'总是调用自己。
第二次尝试(仅更改方法)
public RealNumber<N> add(Number number){
return add(number);
}
首先不是那么好,因为它将允许添加BigDecimals,或其他类似布尔值的东西,第二次引导我到同一个StackOverflowError。所以我改变了:
public RealNumber<N> add(N number){
return add(number);
}
//note the public here
public RealNumber<Double> add(Double number){
return new RealNumber<Double>(doubleValue() + number);
}
//... public RealNumber<Integer, Long, Float> add....
无法在我的TestClass中编译 - &gt; “类型RealNumber的方法add(Double)是不明确的 最后这个工作:
public RealNumber<N> add(Number number){
return add(number);
}
//note the public here
public RealNumber<Double> add(Double number){
return new RealNumber<Double>(doubleValue() + number);
}
//... public RealNumber<Integer, Long, Float> add....
但带来了另外两个问题:此模式允许将双打添加到Ints(导致整数的RealNumber),如果传递BigInteger,Byte或其他Number
,则会导致StackOverflowError。
所以我的主要问题是:
如果每个add
方法都是公共的并且失败,如果它们是私有的,编译器为什么在Test.class中选择正确的方法。
我该怎么做才能解决问题?
答案 0 :(得分:2)
[抱歉,我第一次尝试时并没有完全理解这个问题。 ]
我认为@Rafael没有一个简单的答案,因为@Andrei Bodnarescu指出,类型擦除意味着你在运行时没有N
参数的类型。我认为你必须为add()
的每个子类提供Number
方法的具体实现。
public RealNumber<Integer> add(Integer number) {
return new RealNumber<Integer>(intValue() + number);
}
public RealNumber<Long> add(Long number) {
return new RealNumber<Long>(longValue() + number);
}
如果您不想将整数添加到双打中,那么我猜您需要执行以下操作:
public RealNumber<Integer> add(Integer number){
if (!(this instanceof Integer)) {
throw new IllegalArgumentException("You can't do this...");
}
return new RealNumber<Integer>(intValue() + number);
}
我认为没有任何简单的方法可以解决这个问题。
答案 1 :(得分:2)
:
public RealNumber<N> add(N number){
return add(number);
}
由于类型擦除,方法总是调用自身:在Java泛型中仅用于编译时,它们在运行时不再存在,因此VM实际上不知道N是什么类型,因此它调用最通用的方法可用,即这一个。您必须将类型作为Class作为参数传递给方法,例如:
public RealNumber<N> add(N number,Class<N> numberClass){
return add(number);
}