Java:java.lang.Number的重载(通用)方法

时间:2011-11-08 15:13:49

标签: java generics numbers polymorphism overloading

所以我读了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中选择正确的方法。

我该怎么做才能解决问题?

2 个答案:

答案 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);
    }