如何做一个使用数字加法的模板class(模板扩展数字)?

How to do a template class (where the template extends Number) which use number addition?

你好,我想做一件非常简单的事情。只需为任何数字制作一个模板函数。我实际上只想要 "add" 的能力。在 C++ 中,它真的很微不足道:

template <typename T>
inline T add (T a, T  b) { 
    return a + b; 
}  

int main(int argc, char** argv){
   printf("int: %d\n",add(1,2));
   printf("float: %f\n",add(1.1,2.1));
}

在Java我得到了惨痛的教训。我是 Java 的新手,所以我相信(并希望)我完全错了,并且过度设计了这个。但我唯一想到的是:

public interface IntrfcWowNumbersAdds<T> {
    T add(Number v);
}

public class SuperSmartInteger extends Number implements IntrfcWowNumbersAdds<SuperSmartInteger>{
    private Integer i;
    public SuperSmartInteger(int v) {
        i = v;
    }

    @Override
    public String toString(){
        return ""+i;
    }

    @Override
    public SuperSmartInteger add(Number v) {
        return new SuperSmartInteger(this.intValue()+v.intValue());
    }

    @Override
    public int intValue() {
        return i; // thx god for auto(un)boxing
    }

    @Override
    public long longValue() {
        return i;
    }

    @Override
    public float floatValue() {
        return i;
    }

    @Override
    public double doubleValue() {
        return i;
    }
}

请注意,上面这个疯狂的包装器对于我想使用模板的任何数字(例如双精度、字节等...)都必须做

public class ThreadSafeNum<T extends Number & IntrfcWowNumbersAdds<T>> {
    private T    num;

    public ThreadSafeNum(T n){
        num = n;
    }

    public T add(T v){
        // note in here I plan to do some locking...
        return num = num.add(v);
    }
}

然后我可以将其用作:

SuperSmartInteger i = new SuperSmartInteger(5);
SuperSmartInteger i2 = i.add(6);
System.out.println(""+i2);
ThreadSafeNum<SuperSmartInteger> tsn = new ThreadSafeNum<SuperSmartInteger>(i);
SuperSmartInteger i3 = tsn.add(i2);

我知道当 add() 只是添加时,我可以只使用 + 运算符并依赖自动(取消)装箱。但是我的 add() 方法是为了做一些额外的事情(比如锁)。

那么如何正确地做呢?还是我的方法正确???

像这样作为基础class:

public abstract class Addable<T extends Number,U extends Addable<T,U>> {
  private final T value;
  public Addable( final T value ){ this.value = value; }
  public T getValue(){ return value; }
  public abstract U add( U addend );
}

而这个作为子class:

public class AddableInteger extends Addable<Integer,AddableInteger> {
  public AddableInteger( final Integer value ){
    super( value );
  }

  @Override
  public AddableInteger add( final AddableInteger addend ){
    java.util.Objects.requireNonNull( addend );
    return new AddableInteger( this.getValue() + addend.getValue() );
  }
}

好吧,在 C++ 中起作用的原因是编译器将创建与代码中的调用一样多的函数,并独立编译每个函数以验证“+”是否是一个合理的事情那个特殊情况。这有点像编译器辅助鸭子打字的情况。换句话说,不能保证类型 T 将具有 + 运算符,只有编译器将查看实际调用类型并创建排列这一事实对您有帮助。

请注意,让编译器 "add whatever" 存在一些风险,因为没有接口或契约可以保证语义正确。这就是 class 层次结构带给您的。

这在完全类型安全方面比较棘手,因为继承可能很复杂并且 return 类型需要稍微清楚一些。继承是通常的事情,因此虚方法知道如何添加自己的类型,但在这种情况下,您不能更改 Number.class 的层次结构。

不过,您可以这样做:

public static int addAsInt(Number a, Number b)
{
    a.intValue() + b.intValue();
}

其他 return 类型也一样。这将采用任意两个数字实例并生成一个输出值,假设您想要哪种输出类型。在这种特殊情况下,比创建包装器 classes 更容易一些。