
2016冬天学习记录
---------代码三、计算溢出
刚刚研究了小数计算,现在看看大叔计算要注意的地方
定义一天中的微秒数和毫秒数如下:
final long MICROS_PRE_DAY = 24*60*60*1000*1000;
final long MILLIS_PRE_DAY = 24*60*60*1000;
则输出计算除法时会发现,System.out.println
(MICROS_PRE_DAY/MILLIS_PRE_DAY);
结果为5,而并非我们希望的1000。
事实上,单独输出MICROS_PRE_DAY的时候,
System.out.println(MICROS_PRE_DAY);结果就不对了,这是因为虽然我们long定
义,但是在计算乘积的过程中,实际上是按照int类型处理,在计算完成后才转为
long,但这时已经溢出了,所以于事无补,造成后续计算结果的失误。
为了避免,我们需要在数据溢出之前就将数据强制类型转换为long类型,即有下面
操作:
final long MICROS_PRE_DAY = 24L*60*60*1000*1000;
final long MILLIS_PRE_DAY = 24L*60*60*1000;
这样计算结果就精确无误了。
顺便补充两点注意事项:
一、上面用到的final是将数据定义为long常量,类似于c++的const但实际上两者
有区别,稍加注意即可。
二、虽然用大写L和小写l都能编写long如234L和234l,但为避免混淆,以大写L编
写为上。
/*四到七都被我注释掉了哦,废话比较多不要看
---------谜题四、略(为保证不出现冲突,这里将对所有省略的内容作出简要说
明)
注意事项中的第二点就是《java解惑》的代码四,不做赘述。
---------谜题五、计算十六进制
需要注意的就是八进制和十六进制的运算时,应尽量保证两边都是用long表
示的,以确保运算结果不失去前导。
---------谜题六、类型转换
执行这个操作的时候intln((int)(char)(byte)-1);
类型转化的结果并没有回到-1,这里涉及到不同位数的数据的拓宽和窄化,
(
对这两种拓展有详细说明)但是解决问题的办法我没从书中得到,先在这里做个记
录吧。
---------谜题七、关于一些聪明代码
这个谜题中作者提到了一种先辈们使用过的交换值的办法即(x^y^x)=y,但
是这种办法并没有被java接受,作者提到这个大概是希望我们要养成好的变成习惯
,不要为了一时方便而将自己抛入无尽的bug中,小辈自当谨遵教诲。
*/
---------谜题八、问好冒号表达式
显示这运行一下下面这个代码:
public class Demo{
public static void main(String [] args){
char x='X';
int i = 0;
System.out.print(true?x:0 );
System.out.print(false?i:x);
}
}
我第一反应是XX,但结果是X88,至于为什么,其实条件表达式也是有类型的,这
个类型跟操作数有很大关系,所以最好的办法就是尽可能的保证数据类型一致,这
样就不必为了表达式的类型费脑筋。关于数据类型转换有一点很重要:(自行脑补
一万刻星)
小可转大,大转小会失去精度。
这个诀窍重要到什么程度呢?
public class Demo{
public static void main(String [] args){
char x='X';
int i = 0;
System.out.print(true?x:0 );
System.out.print(false?(char)i:x);
}
}这样就输出XX
public class Demo{
public static void main(String [] args){
char x='X';
int i = 0;
System.out.print(true?(int)x:0 );
System.out.print(false? i:x);
}
}这样改就输出8888。这个琢磨明白就好了。
---------谜题九、复合赋值操作符和简单赋值操作符(一)
作者让我帮他写两行代码,说要让x+=i合法,而x=x+i不合法,
你要不要先想想。
先说上面的问题,答案很简单,把x和i定义成两种不同宽度的数据类型就行
。一直以为x+=i和x=x+i;是一样的,但好像还是有差别的:
但是,嗯,实际上复合赋值操作符会自动将所执行的计算结果转型为其左侧
变量的类型,这个貌似和前面的大数计算的问题(长整除)有点相似,这里又涉及
到了类型转换的问题,我们的口号是:小可转大,大转小会失去精度。所以复合赋
值操作符这种偷偷摸摸的行为会悄悄的在我们的代码里安装一颗炸弹,这样并不稳
妥,为防止类型转换带来的我们还是更喜欢能把问题直接报告出来的简单赋值操作
。
---------谜题十、复合赋值操作符和简单赋值操作符(二)
同样的情况下,现在作者又想让前者非法,后者合法,怎么办?
作者提到,大多数情况下复合赋值操作符都是比简单赋值操作符更不计较,也更容
易出问题,但是由于特殊需要,简单赋值操作符必须做出让步:
还是x+=i和x=x+i,当x是一个字符串时,两个赋值操作符都执行字符串的连接操作
:
System.out.println(x+=i);
System.out.println(x=x +i);
结果:
asdfasd2
asdfasd2
但是,当左侧是对象,x=x +i把字符串连接后的结果记录在对象中,
此时复合赋值操作符则报错,这个稍加注意就好。
Object x="asdfasd";
String i = "asd";
System.out.print(x=x +i);
说来说去,第一章的内容其实就是怎样处理不同操作类型的操作数,还是那句口号
,小可以转大,大转小会失去精度。