为什么我不能用Number接口计算?

时间:2015-04-29 12:02:23

标签: java inheritance interface

我想用这个类来计算平均值:

  public static class AverageValue<T extends Number> {
    T data = 0;  //ERROR: incompatible types: int cannot be converted to T
    int count = 0;
    public AverageValue() {}
    public AverageValue(T data) {
      this.data = data; 
      count = 1;
    }
    public void add(T num) {
      data+=num; //ERROR: bad operand types for binary operator '+'
      count++;
    }
    public T average() {
      return data/(T)count; //ERROR: incompatible types: int cannot be converted to T
    }
  }

如果不抽象数,我真的没有得到为什么我们有接口号码。因为这就是接口所做的事情 - 用数据抽象操作而不保留数据本身。

以上也清楚地表明,你可能无法自己编号实现(例如,对于一些非常怪异的实验性数学程序,数字的大小和精度都无限制。)

我尝试使用Number代替通用T,结果非常相似。唯一的区别是Number x = 0实际上是有效的。

有没有办法欺骗java编译这个或者我必须是一个“专业”java程序员并使用双精度来计算字节数组的平均值?

4 个答案:

答案 0 :(得分:4)

  

如果它没有抽象数字

,我真的没有得到为什么我们有接口Number
为了存储和转换表示,

interface Number确实抽象了数字。它不会为了进行计算而抽象数字,因为结果表示的类型没有很好地定义。

  

以上也清楚地表明,你可能无法自己编号实现(例如,对于一些非常怪异的实验性数学程序,数字的大小和精度都无限制。)

BigDecimal没有任何问题。

  

Number x = 0实际上是有效的。

Integer分配给Number即可。将Integer分配给扩展Number(例如Double)的内容并不正常。这就是为什么会有所不同。

  

有没有办法诱骗java编译这个或者我必须完全延迟专业的Java程序员并使用双精度来计算字节数组的平均值?

计算平均值时,需要指定所需的结果表示。你可以自己抽象出来并提供“averager”ingerface,但是关于所需表示的信息需要以某种方式进入方法:

interface AverageMaker<T extends Number> {
    T initialResult();
    T add(T a, Number b);
    T divideByCount(T a, int b);
}

public static <T extends Number, R extends Number> R averageValue(Iterable<T> items, AverageMaker<R> maker) {
    R res = maker.initialResult();
    int count = 0;
    for (T val : items) {
        res = maker.add(res, val);
        count++;
    }
    return maker.divideByCount(res, count);
}

定义几个普通制造商,如下:

static final AverageMaker<Double> doubleAvg = new AverageMaker<Double>() {
    public Double initialResult() { return 0.0; }
    public Double add(Double a, Number b) { return a + b.doubleValue(); }
    public Double divideByCount(Double a, int b) { return a/b; }
};
static final AverageMaker<Integer> intAvg = new AverageMaker<Integer>() {
    public Integer initialResult() { return 0; }
    public Integer add(Integer a, Number b) { return a + b.intValue(); }
    public Integer divideByCount(Integer a, int b) { return a/b; }
};

现在,您可以在代码中使用它们和averageValue方法:

List<Integer> a = new ArrayList<Integer>();
a.add(4);
a.add(8);
a.add(91);
a.add(18);
double avgDouble = averageValue(a, doubleAvg);
int avgInt = averageValue(a, intAvg);
System.out.println(avgDouble); // Prints 30.25
System.out.println(avgInt);    // Prints 30

Demo.

答案 1 :(得分:1)

您正在混合类(Number)和基本类型(int)。数字类不支持+\等运算符(字符串支持+,但这是一种特殊情况;与C#不同,Java不支持自定义运算符重载)。

BigDecimal类实际上支持“一些真正奇怪的实验性数学程序具有无限大小和精度的数字”,这表明您(以及如何)确实可以拥有自己的Number实现

答案 2 :(得分:1)

您可以在课堂上使用double。由于Integers的平均值为Double,因此这应该是正确的。

public class AverageValue<T extends Number> {

    double data = 0;
    int count = 0;

    public AverageValue() {
    }

    public AverageValue(T data) {
        this.data = data.doubleValue();
        count = 1;
    }

    public void add(T num) {
        data += num.doubleValue();
        count++;
    }

    public double average() {
        return data / count;
    }
}

这个编译。用法:

    AverageValue<Integer> avgInt = new AverageValue<>();
    avgInt.add(1);
    avgInt.add(2);
    avgInt.add(3);
    avgInt.add(4);
    System.out.println(avgInt.average());

    AverageValue<Double> avgDouble = new AverageValue<>();
    avgDouble.add(1.1);
    avgDouble.add(1.2);
    avgDouble.add(1.3);
    avgDouble.add(1.4);
    System.out.println(avgDouble.average());

输出:

2.5
1.25

答案 3 :(得分:0)

  

错误:不兼容的类型:int无法转换为T

var today, someday, text; today = new Date(); someday = new Date(); someday.setFullYear(2100, 0, 14);

if (someday > today) {
    text = "Today is before January 14, 2100."; } else {
    text = "Today is after January 14, 2100."; } document.getElementById("demo").innerHTML = text;
  

错误:二元运算符的错误操作数类型&#39; +&#39;

     

错误:不兼容的类型:int无法转换为T

java中的

不存在运算符重载Why doesn't Java need Operator Overloading?