代码之家  ›  专栏  ›  技术社区  ›  polygenelubricants

在Java中,是否可以为数字框类型编写一个通用的+1方法?

  •  5
  • polygenelubricants  · 技术社区  · 15 年前

    这不是家庭作业。

    是否可以编写一个泛型方法,例如:

    <T extends Number> T plusOne(T num) {
        return num + 1; // DOESN'T COMPILE! How to fix???
    }
    

    少用一堆 instanceof


    第二部分

    以下3种方法编译:

    Integer plusOne(Integer num) {
        return num + 1;
    }   
    Double plusOne(Double num) {
        return num + 1;
    }
    Long plusOne(Long num) {
        return num + 1;
    }
    

    T 仅限于 Integer , Double ,或 Long

    7 回复  |  直到 13 年前
        1
  •  6
  •   polygenelubricants    15 年前

    这方面没有令人满意的解决办法,因为 java.lang.Number 没有指定任何有助于计算 Number

    你必须这么做 instanceof 检查数字框类型,并专门处理每种情况。请注意,您可能会得到 instanceof Number 这不是数字框类型,例如。 BigInteger , AtomicLong ,以及可能未知的子类 Rational 等等)。

    看,这很有欺骗性。这3种方法可能看起来很相似,但自动装箱/取消装箱隐藏了这样一个事实:它们在字节码级别实际上是非常不同的:

    Integer plusOne(Integer);
      Code:
       0:   aload_1
       1:   invokevirtual   #84; //int Integer.intValue()
       4:   iconst_1
       5:   iadd
       6:   invokestatic    #20; //Integer Integer.valueOf(int)
       9:   areturn
    
    Double plusOne(Double);
      Code:
       0:   aload_1
       1:   invokevirtual   #91; //double Double.doubleValue()
       4:   dconst_1
       5:   dadd
       6:   invokestatic    #97; //Double Double.valueOf(double)
       9:   areturn
    
    Long plusOne(Long);
      Code:
       0:   aload_1
       1:   invokevirtual   #102; //Long Long.longValue()
       4:   lconst_1
       5:   ladd
       6:   invokestatic    #108; //Long Long.valueOf(long)
       9:   areturn
    

    xxxValue() valueOf() 方法的类型不同,但指令推送常量 1 iconst_1 , dconst_1 ,和 lconst_1 ).

    即使可以绑定像 <T=Integer|Long|Double> ,这3个方法不能泛化为一个方法,因为它们包含非常不同的指令。

        2
  •  5
  •   Jim Kiley    15 年前

    不是所有的Number子类都可以自动取消装箱。例如,BigDecimal不能自动取消装箱。因此“+”运算符不起作用。

        3
  •  4
  •   Santi P.    15 年前

    在以下所有已知的JDTISEK解决方案中,如果不是已知的,那么它的实现是最可靠的:

    • 它们都可以通过单参数构造函数从字符串表示中创建
    • 它们都没有不能用BigDecimal表示的数字

    public class Test {
    
        @SuppressWarnings("unchecked")
        public static <T extends Number> T plusOne(T num) {
            try {
                Class<?> c = num.getClass();
                Constructor<?> constr = c.getConstructor(String.class);
                BigDecimal b = new BigDecimal(num.toString());
                b = b.add(java.math.BigDecimal.ONE);
                return (T) constr.newInstance(b.toString());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public static void main(String[] args) {
            System.out.println(plusOne(1));
            System.out.println(plusOne(2.3));
            System.out.println(plusOne(2.4E+120));
            System.out.println(plusOne(2L));
            System.out.println(plusOne(4.5f));
            System.out.println(plusOne(new BigInteger("129481092470147019409174091790")));
            System.out.println(plusOne(new BigDecimal("12948109247014701940917.4091790")));
        }
    
    }
    

    返回是使用一个明显不安全的强制转换完成的,但是如果您使用的是某个T的类或T的子类的构造函数,则可以确保它始终是安全的强制转换。

        4
  •  2
  •   Jeff    15 年前

    这并不是泛型的限制。

    public Number plusOne(Number num) {
        return num + 1;
    }
    
        5
  •  1
  •   Bozho    15 年前

    第1部分:

    num + 1 工作时不需要创建这样的方法?这个 +

    Integer n = plusOne(anotherInt);
    

    当您可以:

    Integer n = anotherInt + 1;
    

    底线是-你不能把自动装箱和泛型结合起来。

        6
  •  1
  •   Jay    15 年前

    这里的问题是你的代码必须解除对象的绑定,对原语进行操作,然后重新绑定它。因为Java不知道它是如何编译的,因为它不知道如何编译代码。

    唯一的方法是,如果有一个plusOne函数为Number定义,而没有。

        7
  •  0
  •   Carl Manaster    15 年前

    Java中的算术运算只对原语起作用。你在这里结合了泛型和自动装箱拆箱等。

    推荐文章