今天发现一个奇怪的现象,我根据这个现象写了一个简单的程序:
 
public class Simple {
    public static void main(String[] args) {
        int a=Integer.MIN_VALUE;
        int b=-a;
        
        if (b==a) {
            System.out.println("******b==a*******");
        }else{
            System.out.println("******b!=a*******");
        }
        
        if (b==Integer.MAX_VALUE){
            System.out.println("b==Integer.MAX_VALUE");
        }else {
            System.out.println("b!=Integer.MAX_VALUE");
        }
        
    }
}我知道Integer.MIN_VALUE=-2147483648 而 Integer.MAX_VALUE=2147483647
所以上面程序中b就超出int的范围了,也肯定不等于Integer.MAX_VALUE,
但我的问题是:为什么-Integer.MIN_VALUE还是等与Integer.MIN_VALUE呢???

解决方案 »

  1.   

    我是这样理解的
    -Integer.MIN_VALUE=2147483648
    16位2进制数,2147483648=-2147483648
    所以
    -Integer.MIN_VALUE等与Integer.MIN_VALUE
      

  2.   

    Integer.MIN_VALUE,即 -2147483648,二进制位如下:1000 0000 0000 0000 0000 0000 0000 0000在计算机的运算中,“-”(前缀)运算表示各二制位取反再加1,也就是说 b = -a 在计算机内部是 b = ~a + 1 这样处理的,所以上面的位就变成了:   1000 0000 0000 0000 0000 0000 0000 0000  Integer.MIN_VALUE
    取反 0111 1111 1111 1111 1111 1111 1111 1111 (取反之后变成了 Integer.MAX_VALUE)
    加1 1000 0000 0000 0000 0000 0000 0000 0000  -Integer.MIN_VALUE(与原来的结果一样)
      

  3.   

    Integer.MIN_VALUE,即 -2147483648,二进制位如下: 1000 0000 0000 0000 0000 0000 0000 0000 在计算机的运算中,“-”(前缀)运算表示各二制位取反再加1,也就是说 b = -a 在计算机内部是 b = ~a + 1 这样处理的,所以上面的位就变成了:    1000 0000 0000 0000 0000 0000 0000 0000  Integer.MIN_VALUE 
    取反 0111 1111 1111 1111 1111 1111 1111 1111 (取反之后变成了 Integer.MAX_VALUE) 
    加1 1000 0000 0000 0000 0000 0000 0000 0000  -Integer.MIN_VALUE(与原来的结果一样)---------------------------------
    确实
      

  4.   

    哦,我错了
    Java中对负数的表示方法是把绝对值得原码按位取反然后加1
      

  5.   

    1,数现在恐怕除了卖碳翁,地球上的人都知道计算机里用的是二进制了吧。
    这里只想提醒重视一番,本人觉得这里是根本,所以可能说得会多些。
    编程语言中,都有整数和浮点数类型
    在JAVA里,整数有byte,short,int,long,浮点数则为float,double;
    1.1 整数1.1.1表示
    JAVA中整数采有符号二进制补码表示,补码对正数没什么好说的,但对负数还是要
    注意一下:
        byte a=-3;
    十进制        二进制
    3        0 0000011
    -3        1 1111101
    对我们来说,求负数(-10)的补码表示可简单采取以下步骤:
    1,用原码表示相应的负数(1 0001010)
    2,从右到左,找出第一个为1的位(倒数第二位)
    3,将第一个为1的位和它所有的低位保留不变(不变)
    4,将它的高位(不含符号位)取反(1 1110110)
    另外还有一条,原码的补码的补码,就是原码,你可求一下-21的补码表示试试
    根据JAVA语言规范,整数表示的范围
    byte:    -128---127
    short:    -32768---32767
    int:    -2147483648---2147483647
    long:    -9223372036854775808-----9223372036854775807
    以byte为例:
    0 0000000-------0 1111111=======>0->127
    1 0000000-------1 1111111=======>-128->-1
    可以这么说:2的8次方代表的256个数,“小”的一半表示了0和正数,“大“的一半表示负数
    并且两部分都是从小到大排列。1.1.2运算
    咱们都知道计算机采用的都是加法,那么JAVA对5-3怎么处理呢?
    十进制        二进制
    5        0 0000101    +
    -3        1 1111101
    结果          1 0 0000010
    最高位1溢出舍去,结果便为2了(0 0000010)可见采用补码表示,计算机可以容易将
    各种整数运算用加法操作1.1.3文法(Lexical)
    我们编写的JAVA源程序,只不过是简单的文本,计算机怎么知道你写的哪个是数哪个
    是串呢?
    这就是编译器的功能了,它根据文法树(好像叫什么AST)分析你的源代码结构,来区
    分你想表示的内容。
    请试试编译以下代码:
    byte a=128;
    long b=2147483648;
    我们都不能通过,但错误原因是不一样的
    默认情况下,文本数字代表的是int型(-_-)!
    对于byte a=128,如果文本代表的数值在byte范围内(如byte a=1),则JVM可以自动进
    行类型转换,而不在编译期出错,反之,丢失精度出错。
    对于long b=2147483648;虽然2147483648在long的范转内,但由于2147483648代表的是
    int型,越界出错。
    若想编译通过,可以改成:
    byte a=(byte)128;
    long b=2147483648L;
    问题:为什么byte a=1;a=a+1;出错,而byte a=1;a+=1;或a++;不出错?
    这时因为,表达式的运算中将a和1作为int处理的,故会出错应是a=(byte)(a+1);
    而a++和a+=1是复合读取操作,JVM会自动做类型转换处理.1.1.4移位运算
    JAVA提供了三个移位运算符<<,>>,>>>
    要注意两点,<<和>>是带符号扩展的,而>>>不是(试试int a=-1;a=a>>1和a=-1;a=a>>>1)
    另外移位是循环移位的,这好象和c中的不一样(试试int a=1,a<<32在java和vc中的结果)1.2 符点数
    相对整数而言,符点数我们用得没那么多,但绝不能说它不重要
    1.2.1表示
    JAVA支持的浮点数类型为float,double下面是它们的表示范围
    1.40239846e-45f ------3.40282347e+38f(float正数)
    4.94065645841246544e-324-----1.79769313486231570e+308(double正数)
    其中,float的32位的分布为
    符号位(1)    指数位(8)    尾数
    s        eeeeeeee    mmmmmmmmmmmmmmmmmmmmmmm
    表示的符号为: 符号*2的指数次方*尾数
    1.2.2文法(Lexical)
    浮点数默认情况下均为double型,所以
    float a=1.0编译不通
    应为
    float a=1.0f;2,字符,串JAVA中的字符是以unicode表示的,对unicode的讨论需要较长篇幅,有兴趣者可参考
    相关网上文章,这里想说一下字符串拘留问题。
    引出:
        String s=new String("abcde");创建了几个对象?
    好像是从网上留传的面试题里,发现了这个问题,答案说是两个,为了究明就里,我
    好找了一翻。
    我们写在源代码中的字串,是以常量的形式保存在class文件中,大家都知道字符串在
    java中是完备的不可变不可继承的String类的对象,这个字串对应的对象是在JVM运行
    时解析到字符串时建立的,例如:
        String s1="hello";
        String s2="hello";
    当JVM运行第一行代码的时候,它就先从类的常量池里取出"hello",并按照这个字符序
    列创建一个String类的对象,然后当这个对象的引用赋给局部变量s1,而且它会“拘留”
    这个对象的引用,放在内部的一个表中,接着JVM运行第二行代码,这个时候它首先检
    查内部表中的对象引用指向的对象的字符序列是否有新出现的字符序列一致的,如上所
    示,结果查到s1所指象的对象符合,于是它便不再重新生成一个新的String实例,而是
    将s1所代表的引用赋给s2;
    然后你在运行
        System.out.println(s1==s2);
    可以确定s1和s2的确指向同一对象。
    回到原来问题:
        String s=new String("hello");创建了几个对象?
    这里调用了String的String(String original)的构造函数,因为new操作是确定会生成
    一个新对象的,如果"hello"是第一次出现在要执行的方法中,JVM就会先创造一个对象
    代表"hello",所以可以说这行代码创建了两个对象,但如果不是第一次出现这话就不对
    了。3,运算符,表达式这些东西恐怕大家也看厌了,但还是有些细节提醒一下
    ()这个符号具体来说有三个作有,
    一是操作数分组如:3*(2+5)之类
    二是方法调用如:sort(a)
    三是类型转换如:(byte)128
    需要注意的是一、二的优先级是最高的,三要比它们低,如:
    (Object)a.b(),((Object)a).b()的差别
    另外表达式的解析顺序是自左到右的(好像是废话)
    结合性(特别是赋值)也很容易让大家混淆表达式结果
    其它不多说了,不过给几个示例代码,你可以试试结果和你想像的差别:
    (1)
            int i = 2;
            int j = (i=3) * i;
            System.out.println(j);
    (2)
            int a = 9;
            a += (a = 3);                                    
            System.out.println(a);
            int b = 9;
            b = b + (b = 3);                                
            System.out.println(b);
    (3)
            int a=3;
            int b[]=new int[5];
            b(a)=a=6;//应该是方括号,但没法正确显示
            for(int i=0;i<b.length;i++){
                System.out.println(b[i]);
            }
    (4)
            System.out.println(3+5+" hello");
            System.out.println("hello "+3+5);
      

  6.   

    谢谢各位的解答,但我还有一个问题,-b已经超出int的范围了,为什么程序没有报错(或是抛出异常)?而是正常运行?
      

  7.   

    -b 没有超出范围,在 int 范围之内的啊。再说就算超出 int 范围了,也不会报错,只出溢出(就是把超过 32 的给扔了),只截取 32 位。