java.lang.Number 没有实现“+”或任何其他运算符?

Posted

技术标签:

【中文标题】java.lang.Number 没有实现“+”或任何其他运算符?【英文标题】:java.lang.Number doesn't implement "+" or any other operators? 【发布时间】:2012-02-15 23:55:57 【问题描述】:

我正在创建一个类,它应该能够与任何类型的数字(float、int 等)的数组一起使用,所以这是我拥有的一种方法:

// T extends Number
public synchronized T[] average() 
    Number[] ret = new Number[queue[0].length];
    for (int i = 0; i < ret.length; ++i) 
        for (int j = 0; j < size; ++j) 
            ret[i] += queue[j][i]; // WTF ERROR?!
        
        ret[i] /= size; // WTF ERROR?!
    
    return (T[])ret;

除了这不会编译,因为“数字”没有实现“+=”或“/=”运算符。更糟糕的是,Java 的 Number 类甚至没有实现最基本的运算符,如“+”或“-”!如果java不让我编译它,我怎么能创建一个返回数字数组平均值的方法,因为它认为不能添加数字?!?!

【问题讨论】:

Java 没有像 C++ 这样的重载运算符。它所拥有的是方法。例如,java.lang.BigInteger 有一个名为“add”的方法。 欢迎来到 Java,这里的操作符不是函数。此外,您应该了解type erasure,因为Java 中的泛型根本不像C++ 中的模板那样工作。 顺便说一下,数字是抽象的。你甚至无法实例化它。 Nothing 实现了操作符;它们是语言/句法结构。字符串是特殊情况下的语法糖。 @PaulTomblin 除了+ 能够连接字符串 【参考方案1】:

您误解了 Java 中数字的工作方式。 Number 类是数字包装类(IntegerFloat 等)的超类,可用于将原始类型(intfloat 等)表示为对象,但它确实 不能使用通常的算术运算符。

如果您打算使用算术运算符,请使用原始类型。如果您需要构建适用于所有数字数据类型的“通用”方法,您别无选择,只能构建同一方法的多个重载版本,每个数据类型一个,例如:

public  float[] average(float[][]  queue) ...
public double[] average(double[][] queue) ...

还要注意,像这样的代码似乎适用于包装器类型:

Integer i = 0;
i += 1;
System.out.println(i);

... 但在底层,Java 自动为 boxing and unboxing Integer,因为 += 运算符仅适用于原始类型。它之所以有效是因为我们明确指出该数字是Integer,但它不适用于Number,因为Java 需要准确地知道它正在处理的数字类型什么执行装箱/拆箱。

【讨论】:

除了不使用算术运算符之外,Number API 不提供任何执行算术的方法。【参考方案2】:

您需要将数字转换为原始类型,然后算术运算符才能工作。您会注意到Number 确实有doubleValueintValue 等......

或者,您可以转换为BigDecimal,并使用该类上定义的算术方法(不是+- 等,而是addmultiply , 等等....)。这种方法会更准确(如果您需要最佳准确度,请使用BigDecimal),因为浮点数和双精度数仅表示一组离散的数值。请记住,BigDecimal 是不可变的,因此您始终需要将操作的结果分配给引用。

【讨论】:

如果他要明确转换为doubleint 等,那么他到底为什么要使用Number 开头呢?我不认为这是解决方案。【参考方案3】:

我想这就是你想要的

public synchronized average()   
    double ret = new double[queue[0].length];  
    for (int i = 0; i < ret.length; ++i)   
        for (int j = 0; j < size; ++j)   
            ret[i] += queue[j][i];  
          
        ret[i] /= size;  
      
    return ret;  

【讨论】:

【参考方案4】:

很遗憾,你不能。算术运算符仅适用于原始类型(这要归功于其包装器上的自动装箱和自动拆箱)。您必须为需要该方法处理的所有原始类型覆盖给定的方法,就像在许多 JDK 类中所做的那样。

【讨论】:

【参考方案5】:

在 Java 中,算术运算符仅适用于原始类型。这里的问题是 Java 具有这些原始类型的类表示,并且通过称为 autoboxing 的功能从一个到另一个的切换通常是隐式的。

在这种情况下,您需要为所需的算术运算类型实现方法,可能必须为每个运算传入的每个可能的数字类型创建 overloaded methods。

【讨论】:

【参考方案6】:

由于所有可能的byteshortcharintfloatdouble 都可以表示为double,因此它的效率更高(因为它是一个原语而不是任何对象)并且更易于使用 double 而不是 Number 如果您需要准确的 long 或 BigDecimal 或 BigInteger,则需要特定的类型。

【讨论】:

@KennethNoland 你能举个例子说明这些类型的值不能存储在 double 中而不丢失精度吗? double 至少有 53 位精度,足以存储任何这些类型。【参考方案7】:
public int showAllNum(Number i, Number j) 
    return (int) (i.doubleValue()+j.doubleValue()); 

【讨论】:

您应该正确格式化并解释您的答案。

以上是关于java.lang.Number 没有实现“+”或任何其他运算符?的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码分析-Integer

java.lang.Number解读

Java泛型Number能比较大小吗?

2.20专项测试复盘

J2EE面试题集锦

intValue()的用法