Java算术运算中的int和long有什么区别?

12

我在谷歌上做了一些搜索,但似乎找不到我需要的东西。我试图找到有关Java中算术运算方式的详细信息。例如,如果将两个long相加,是否使用与将两个int相加时相同的加法运算符?还有,当您在这样的算术表达式中混合long和int时,其内部发生了什么:

long result;
long operand a = 1;
int operand b = 999999999;

result = a + b;

如果有人能够解释一下这个问题,并且提供相关文章的链接,那将是非常棒的。谢谢!

编辑:感谢到目前为止的回复。同时,只要你将结果赋值给表达式中最宽的原始类型的变量,使用不同的基本类型执行算术运算是否安全?


2
这不是一个论坛,回答你问题的人并不知道你是否有后续。至于你的编辑: 如果变量不是足够宽的原始类型,则Java不允许将操作的结果分配给变量。换句话说,您不能将“0L + 1”的结果分配给int而不进行特定的int转换。 - Tim Bender
它并不完全安全,因为许多操作可能会导致下溢或上溢。尝试 Long.MAX_VALUE + 1。然而,如果你分配给最宽的类型,它总是可以编译的。 - Peter Lawrey
7个回答

15

当混合使用类型时,int会自动扩展为long,然后将两个long相加以产生结果。 Java语言规范解释了包含不同原始类型的操作过程。

具体来说,这些是每种原始类型在不需要转换的情况下扩展到的类型:

  • byte扩展为short、int、long、float或double
  • short扩展为int、long、float或double
  • char扩展为int、long、float或double
  • int扩展为long、float或double
  • long扩展为float或double
  • float扩展为double

我认为这将修复损坏的链接:http://docs.oracle.com/javase/specs/jls/se5.0/html/conversions.html#5.6 - Chris

7

参见:转换和提升

根据此,您的int会被提升为long,然后进行评估。

同样地,对于其他基本类型,例如int+double,也会发生类似情况。

System.out( 1 + 2.0 );// prints 3.0 a double

关于加法运算符,它们的使用方式基本相同,但我没有相应的参考资料。通过查看编译器源码,我们可以发现它们是不同的。具体来说,整数加法使用iadd,而长整型加法使用ladd。以下是示例代码:
$cat Addition.java 
public class Addition {
    public static void main( String [] args ) {
        int  a  = Integer.parseInt(args[0]);
        long b = Long.parseLong(args[0]);
        // int addition 
        int  c  = a + a;
        // long addition 
        long d = a + b;
    }
}
$javac Addition.java 
$

编译后生成的字节码如下所示:

$javap -c Addition 
Compiled from "Addition.java"
public class Addition extends java.lang.Object{
public Addition();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   iconst_0
   2:   aaload
   3:   invokestatic    #2; //Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
   6:   istore_1
   7:   aload_0
   8:   iconst_0
   9:   aaload
   10:  invokestatic    #3; //Method java/lang/Long.parseLong:(Ljava/lang/String;)J
   13:  lstore_2
   14:  iload_1
   15:  iload_1
   16:  iadd
   17:  istore  4
   19:  iload_1
   20:  i2l
   21:  lload_2
   22:  ladd
   23:  lstore  5
   25:  return

}

看一下第 16 行,它写着:iadd(用于 int 相加),而第 22 行则写着 ladd(用于 long 相加)。
此外,只要你将表达式赋值给最宽的原始类型变量,使用不同原始类型进行算术运算也是“安全”的。但是,会丢失信息。
例如,尝试将 Integer.MAX_VALUE 加上 Integer.MAX_VALUE,或者 int x = ( int ) ( Long.MAX_VALUE - 1 );

3
此外,如果你在表达式中赋值给最宽的原始类型变量,使用不同的原始类型进行算术运算是否安全呢?
这取决于你所说的“安全”。它肯定不会避免你需要考虑溢出的可能性。

3

2
int a=5;  
long b=10;  
a+=b;  
System.out.println(a);

主要区别在于使用 a = a + b 时不进行类型转换,编译器因为未进行类型转换而报错。 但是使用 a += b 时,实际上是将 b 转换为与 a 兼容的类型后再进行操作。

它在从 longint 做一个不可见的下传转换,有可能会抛弃信息?我在 java.io.ByteArrayInputStream#skip(long) 中偶然发现了这个问题,并且惊讶了一下。以前从未见过这种情况。 - nilskp

2
这个简单的例子可以澄清在Java中算术运算时数据类型转换的疑惑。
    byte a = 1;
    short b = 1;
    System.out.println(a+b);                     //Output = 2
    Object o = a+b;                              //Object becomes int
    System.out.println(o.getClass().getName());  //Output = java.lang.Integer

    int c = 1;
    System.out.println(a+b+c);                   //Output = 3
    o = a+b+c;                                   //Object becomes int
    System.out.println(o.getClass().getName());  //Output = java.lang.Integer

    long d = 1l;
    System.out.println(a+b+c+d);                 //Output = 4
    o = a+b+c+d;                                 //Object becomes long
    System.out.println(o.getClass().getName());  //Output = java.lang.Long

    float e = 1.0f;
    System.out.println(a+b+c+d+e);               //Output = 5.0
    o = a+b+c+d+e;                               //Object becomes float
    System.out.println(o.getClass().getName());  //Output = java.lang.Float

    double f = 1.0;
    System.out.println(a+b+c+d+e+f);             //Output = 6.0
    o = a+b+c+d+e+f;                             //Object becomes double
    System.out.println(o.getClass().getName());  //Output = java.lang.Double

以下是Java中按范围排序的数据类型顺序:
    byte<short<int<long<float<double

这是扩大转换发生的顺序。
注意:float具有比long更大的范围,但尺寸更小。

0
答案指出了算术提升。但是在这个基础上,我陷入了以下陷阱(我真是太丢人了),我想在这里指出: 如果有两个以上的操作数,我觉得计算是从左到右进行的,并且如果焦点中的实际两个操作数具有不同的类型,则会发生算术提升。 因此,以下代码对s1和s2产生不同的结果。我对此的解释是: 首先计算s1,将a和b作为两个整数相加(并发生溢出),然后将c(长整型)添加到该结果中。 当计算s2时,首先将c和b相加(作为长整型),然后添加a(作为长整型推广),因此不会发生溢出。
final int a = Integer.MAX_VALUE;
final int b = 1;
final long c = 1L;
final long s1 = a + b + c;
final long s2 = c + b + a;
System.out.println("s1=" + s1 + ", s2=" + s2);

输出将是: s1=-2147483647,s2=2147483649


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接