Java问题总结1

一、关于原码、反码、补码问题。

1.原码

将一个整数转换成二进制形式,就是其原码。例如short a = 6; a 的原码就是0000 0000 0000 0110;更改 a 的值a = -18; 此时 a 的原码就是1000 0000 0001 0010

通俗的理解,原码就是一个整数本来的二进制形式。

2.反码

对于正数,它的反码就是其原码(原码和反码相同);负数的反码是将原码中除符号位以外的所有位(数值位)取反,也就是 0 变成 1,1 变成 0。例如short a = 6; a 的原码和反码都是0000 0000 0000 0110;更改 a 的值a = -18; 此时 a 的反码是1111 1111 1110 1101

3.补码

对于正数,它的补码就是其原码(原码、反码、补码都相同);负数的补码是其反码加 1。例如short a = 6; a 的原码、反码、补码都是0000 0000 0000 0110;更改 a 的值a = -18; 此时 a 的补码是1111 1111 1110 1110

可以认为,补码是在反码的基础上打了一个补丁,进行了一下修正,所以叫“补码”。

原码、反码、补码的概念只对负数有实际意义,对于正数,原码、反码、补码都是一样的。

二、其他遇到问题。

1.枚举基本用法

仔细阅读示例: EnumTest.java,运行它,分析运行结果?代码如下

 1 public static void main(String[] args) {
 2         Size s=Size.SMALL;
 3         Size t=Size.LARGE;
 4         //s和t引用同一个对象?
 5         System.out.println(s==t);  //
 6         //是原始数据类型吗?
 7         System.out.println(s.getClass().isPrimitive());
 8         //从字符串中转换
 9         Size u=Size.valueOf("SMALL");
10         System.out.println(s==u);  //true
11         //列出它的所有值ֵ
12         for(Size value:Size.values()){
13             System.out.println(value);
14         }
15     }
16      enum Size{SMALL,MEDIUM,LARGE};

运行结果    分析

false      s和t引用的并非同一个对象,s引用的是SMALL,t引用的是LARGE。
false      枚举类型并非原始数据类型(原始类型一共有8种,它们分别是char,boolean,byte,short,int,long,float,double)
true        调用valueOf(“SMALL”)将返回 Size.SMALL,将字符串转换为枚举。

SMALL     利用values()遍历输出枚举。

MEDIUM
LARGE

2.println()的输出问题

1     int X=100;
2     int Y=200;
3     System.out.println("X+Y="+X+Y);
4     System.out.println(X+Y+"=X+Y");

输出结果为

1 X+Y=100200
2 300=X+Y

两个+的意义不同,第一个+是连接运算符,第二个是加法运算符。

若加括号改变运算优先级,改为

System.out.println("X+Y="+(X+Y));

则输出

X+Y=300

3.double类型计算结果不精确问题

1         System.out.println("0.05 + 0.01 = " + (0.05 + 0.01));
2         System.out.println("1.0 - 0.42 = " + (1.0 - 0.42));
3         System.out.println("4.015 * 100 = " + (4.015 * 100));
4         System.out.println("123.3 / 100 = " + (123.3 / 100));

结果为

1 0.05 + 0.01 = 0.060000000000000005
2 1.0 - 0.42 = 0.5800000000000001
3 4.015 * 100 = 401.49999999999994
4 123.3 / 100 = 1.2329999999999999

会清楚的发现每个关于double的计算都有一点点误差。

原因涉及到二进制与十进制的转换问题。

N进制可以理解为:数值×基数的幂,例如我们熟悉的十进制数123.4=1×10²+2×10+3×(10的0次幂)+4×(10的-1次幂);

其它进制的也是同理,例如二进制数11.01=1×2+1×(2的0次幂)+0+1×(2的-2次幂)=十进制的3.25。

double类型的数值占用64bit,即64个二进制数,除去最高位表示正负符号的位,在最低位上一定会与实际数据存在误差(除非实际数据恰好是2的n次方)。

解决方案:

使用BigDecimal类 Demo:TestBigDecimal.java

import java.math.BigDecimal;

在构建BigDecimal对象时应使用字符串而不是double数值,否则,仍有可能引发计算精度问题。

 1         BigDecimal f1 = new BigDecimal("0.05");
 2         BigDecimal f2 = BigDecimal.valueOf(0.01);
 3         BigDecimal f3 = new BigDecimal(0.05);
 4         System.out.println("下面使用String作为BigDecimal构造器参数的计算结果:");
 5         System.out.println("0.05 + 0.01 = " + f1.add(f2));
 6         System.out.println("0.05 - 0.01 = " + f1.subtract(f2));
 7         System.out.println("0.05 * 0.01 = " + f1.multiply(f2));
 8         System.out.println("0.05 / 0.01 = " + f1.divide(f2));
 9         System.out.println("下面使用double作为BigDecimal构造器参数的计算结果:");
10         System.out.println("0.05 + 0.01 = " + f3.add(f2));
11         System.out.println("0.05 - 0.01 = " + f3.subtract(f2));
12         System.out.println("0.05 * 0.01 = " + f3.multiply(f2));
13         System.out.println("0.05 / 0.01 = " + f3.divide(f2));

运行结果

 1 下面使用String作为BigDecimal构造器参数的计算结果:
 2 0.05 + 0.01 = 0.06
 3 0.05 - 0.01 = 0.04
 4 0.05 * 0.01 = 0.0005
 5 0.05 / 0.01 = 5
 6 下面使用double作为BigDecimal构造器参数的计算结果:
 7 0.05 + 0.01 = 0.06000000000000000277555756156289135105907917022705078125
 8 0.05 - 0.01 = 0.04000000000000000277555756156289135105907917022705078125
 9 0.05 * 0.01 = 0.0005000000000000000277555756156289135105907917022705078125
10 0.05 / 0.01 = 5.000000000000000277555756156289135105907917022705078125

 

posted @ 2022-09-12 10:27  lao_bing  阅读(30)  评论(0)    收藏  举报