如何做一个使用数字加法的模板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 更容易一些。
你好,我想做一件非常简单的事情。只需为任何数字制作一个模板函数。我实际上只想要 "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 更容易一些。