表达式之谜总结

一、奇数表达问题

问题:我们经常会认为i%2==1能够判断是否为奇数。

分析:

(1)取模操作符(%):当取余操作返回一个非零的结果时,这个结果一定和左操作符有相同的符号。

举例:

  • 3%2=1;
  • -3%2=-1;    对应前面的定义,由于左操作符是-3,因此结果应该也是负数。

(2)初步结果:通过i%2==0来判断是否为奇数。

(3)位运算:位运算比一般的算术运算速度快的多。一般偶数的二进制最低位都是0,不管是用原码、补码。

最终结果:i&1)!=0

例程:

import java.util.Scanner;
public class PuzzleDemo01{
	public static void main(String args[]){
		Scanner in =  new Scanner(System.in);
		System.out.print("输入一个整数:"); 
		int a = in.nextInt();
		System.out.println("");
		System.out.println("i%2==1 -->"+isOdd1(a));
		long begin1 = System.nanoTime(); 
		System.out.println("i%2!=0 -->"+isOdd2(a));
		long begin2 = System.nanoTime(); 
		System.out.println("i&1!=0 -->"+isOdd3(a));
		long begin3 = System.nanoTime(); 
		System.out.println("isOdd2的运算时间:"+(begin2-begin1)+" nano");
		System.out.println("isOdd3的运算时间:"+(begin3-begin2)+" nano");
		
		
	}
	public static boolean isOdd1(int a){
		return a%2==1;
	}
	public static boolean isOdd2(int a){
		return a%2!=0;
	}
	public static boolean isOdd3(int a){
		return (a&1)!=0;
	}
}
/*
测试结果:
输入一个整数:-3

i%2==1 -->false
i%2!=0 -->true
i&1!=0 -->true
isOdd2的运算时间:378819 nano
isOdd3的运算时间:368762 nano
*/


二、二进制浮点数运算的精度问题

问题:2.00-1.10的结果是什么?

分析:

(1)看起来好像很明确是0.90,但是实际上输出的是0.899999。原因:1.10不能被精确的表示成一个double。

(2)因此double和float不适用于精确计算。

(3)java.math.BigDecimal用于精确计算。

(4)用BigDecimal(String)的构造器,而不要用BigDecimal(double)的构造器,因为后者有不可预知性。

最终结果:

new BigDecimal("2.00").subtract(new BigDecimal("1.10"));

import java.math.BigDecimal;
public class PuzzleDemo02{
	public static void main(String args[]){
		System.out.println("*******一般的浮点数运算:*******"); 
		System.out.println(2.00-1.10);	//0.8999999999999999
		BigDecimal d1 = new BigDecimal("2.00");
		BigDecimal d2 = new BigDecimal("1.10");
		BigDecimal result = d1.subtract(d2);
		System.out.println("*******运用全精度后:********"); 
		System.out.println(result);		//0.90

	}
}


三、默认类型问题

问题:long a = 24*60*60*1000*1000;的结果是多少?

分析:

(1)默认来说一个整数的类型就是int,如果是long的话要加L。

(2)以上的运算会先是int的乘法,乘完的结果再转换成long类型,这并不能避免溢出。

(3)int是4字节,因此能表示-231-1 ~231,而上面的运算远远超出了这个范围,因此溢出。

最终结果:

long a = 24L*60*60*1000*1000;

public class PuzzleDemo03{
	public static void main(String args[]){
		long MICROS_PER_DAY_ORIGINAL = 24 * 60 * 60 * 1000 * 1000;
		
		long MILLIS_PER_DAY_ORIGINAL = 24 * 60 * 60 * 1000;
		System.out.println("最初的结果:"
						+MICROS_PER_DAY_ORIGINAL/MILLIS_PER_DAY_ORIGINAL);//5
		long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
		long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
		System.out.println("改正后的结果:"
						+MICROS_PER_DAY/MILLIS_PER_DAY);	//1000
		System.out.println("溢出的结果   -->  24 * 60 * 60 * 1000 * 1000="+MICROS_PER_DAY_ORIGINAL); //500654080
		System.out.println("不溢出的结果 -->  24L * 60 * 60 * 1000 * 1000="+MICROS_PER_DAY);  //86400000000
		
	}
}


四、长整数的表示问题 l还是L?

因为在一般的1和l是差不多的,比如:


 最终结果:

(1)在表示long类型的数时要用L.

(2)在表示变量时不能光用 l(小写的L) 表示.

public class PuzzleDemo04{
	public static void main(String args[]){
		System.out.println("12345+5432l="+(12345+5432l));
		System.out.println("12345+54321="+(12345+54321)); 
		System.out.println("12345+5432L="+(12345+5432L)); 
	}
}
/*
12345+5432l=17777
12345+54321=66666
12345+5432L=17777
*/

五、符号扩展和零扩展

问题1:long a  = 0xcafebabe;中a的十六进制是多少呢?

分析:

(1)对于有符号数进行扩展时,就需要进行符号扩展。而对于无符号数(char)则采用零扩展。

(2)十六进制和八进制的int型时当最高位是1时,就是负数,符号扩展则高位填1.

最终结果:

结果是0xffffffffcafebabe而不是0x00000000cafebabe;

public class PuzzleDemo05{
	public static void main(String args[]){
		int a = 0xcafebabe;
		long b = a;
		System.out.println(a + " --> " + Integer.toHexString(a));
		System.out.println(b + " --> " + Long.toHexString(b)); 
		long c = 0x100000000L;
		System.out.println("0x100000000L+0xcafebabe="+Long.toHexString(c+b)); 
		long d = 0xcafebabeL;
		System.out.println("0x100000000L+0xcafebabeL="+Long.toHexString(c+d)); 
	}
}
/*
-889275714 --> cafebabe
-889275714 --> ffffffffcafebabe
0x100000000L+0xcafebabe=cafebabe
0x100000000L+0xcafebabeL=1cafebabe
*/


问题2:int a = (int)(char)-1;的结果是多少?

分析:

(1)-1是int类型的,转换成char,只需要截断即可,得0xffff.

(2)因为char是无符号的,因此零扩展,则a=0x0000ffff,即65535.

最终结果:

a=65535.

public class PuzzleDemo06{
	public static void main(String args[]){
		System.out.println((int)(char)(byte)-1);
		int i = -1;
		char c = (char)i;
		int j = c & 0xffff;		//无符号扩展
		int j2 = c;				//无符号扩展
		int k = (short)c;		//有符号扩展
		System.out.println("无符号扩展1:"+j);	
		System.out.println("无符号扩展2:"+j2); 
		System.out.println("有符号扩展1:"+k); 
	}
}


总结:

(1)我们对于类型转换的扩展问题需要注释好意义。

(2)对于无符号扩展也可以通过位掩码来进行完成。

比如:

short s = -1;

int i = s&0xffff;    //由于0xffff是int型的,因此s先进行符号扩展成int型,然后进行与,即把高位清除。 

六、条件表达式的规则?:

问题:

int i =0;

true? 'x':i;的结果是多少?

A?B:C

1.如果B和C具有相同的类型,则返回的就是B和C的类型。

2.如果一个操作数的类型是T(byte,int,char等),另一个是一个常量表达式,则返回的类型就是T。

3.否则对操作数类型进行二进制数字的提升,返回的类型就是B和C被二进制提升后的类型。

例如:

int i =0;

true? 'x':i;这个由定理2,可以得出结果是int类型,因此结果是‘x’的ASCII码:120;

结论:尽量将B和C的类型相同。

public class PuzzleDemo08{
	public static void main(String args[]){
		char x = 'X';
		int i = 0;
		System.out.println(true ? x : 0);	//x是char类型,0是常量,因此返回char类型
		System.out.println(false? i : x);	//i是int变量,'x'是常量,因此返回int
		System.out.println(true? 'x': i);	//i是int变量,'x'是常量,因此返回int
		final int j = 1;
		System.out.println(true?x:j);		//x是char类型,而j是常量,因此返回char类型
	}
}

?:在jdk1.4和jdk1.5的区别:

在1.4中,当第二个操作数和第三个操作数都是引用类型时,条件操作符要求一个必须是另一个的子类型。

5.0中,第二第三个操作数是引用类型时,返回的结果是两类型的最小公共超类。

七、x+=i和x=x+i相等?不!

 x+=i等价于x=(Typex)(x+i)    从中看出,中间还有一个隐式的类型转换。

如果 x是short类型,i是int类型,则x+=i    等价于    x=(short)(x+i);

而x=x+i;则没有这个隐式转换,因此如果x的类型的宽度比i的类型的宽度小,则会发生x=x+i的编译错误,而x+=i不会有错。

public class PuzzleDemo09{
	public static void main(String args[]){
	    short x=0;
		int i=123456;
		x += i;		//合法
		System.out.println(x);
		x=0;
		x = (short)(x + i);	//x=x+i不合法
		System.out.println(x); 
	}
}
//x+=i  等价于 x=(Typex)(x+i);


但是复合的赋值操作符有一个限制:

(1)左操作数和右操作数都必须是基本数据类型或包装类

(2)如果左操作数的类型是String,则右操作数没有限制。

(3)左操作数不能是其他引用数据类型。

而x=x+i却没有这个限制。

public class PuzzleDemo10{
	public static void main(String args[]){
		String i = "abc";
		Object x = "cba";
		//x+=i;	不合法
		x=x+i;	//合法
		System.out.println(x); 
	}
}


 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 · · · · · · 第1 章绪论    1 第2 章达式    5 题1:奇数性    5 题2:找零时刻    7 题3:长整除    9 题4:初级问题    11 题5:十六进制的趣事    13 题6:多重转型    15 题7:互换内容    17 题8:Dos Equis     19 题9:半斤    21 题10:八两    23 第3 章字符之    25 题11:最后的笑声    25 题12:ABC     27 题13:动物庄园    29 题14:转义字符的溃败  31 题15:令人晕头转向的Hello   33 题16:行打印程序    35 题17:嗯?     37 题18:字符串奶酪    39 题19:漂亮的火花(块注释符)  41 题20:我的类是什么    43 题21:我的类是什么?镜头2   45 题22:URL的愚弄    47 题23:不劳无获    49 第4 章循环之    53 题24:尽情享受每一个字节  53 题25:无情的增量操作  55 题26:在循环中  57 题27:变幻莫测的i值  59 题28:循环者  61 题29:循环者的新娘  63 题30:循环者的爱子  65 题31:循环者的鬼魂  67 题32:循环者的诅咒  69 题33:循环者遇到了狼人  .71 题34:被计数击倒了  73 题35:分钟计数器  .75 第5 章异常之    77 题36:优柔寡断  77 题37:极端不可思议  79 题38:不受欢迎的宾客  81 题39:您好,再见  .83 题40:不情愿的构造器  85 题41:字段和流  87 题42:异常为循环而抛  89 题43:异常地危险  93 题44:删除类  97 题45:令人疲惫不堪的测验  101 第6 章类之    105 题46:令人混淆的构造器案例  105 题47:啊呀!狸猫变犬子  .107 题48:我所得到的都是静态的  109 题49:比生命更大  .111 题50:不是你的类型  113 题51:要点何在  115 题52:总和的玩笑  .119 题53:做你的事吧  .123 题54:Null与Void   .125 题55:特创论  127 第7 章库之    131 题56:大问题    131 题57:名字里有什么    133 题58:产生它的散列码  137 题59:差是什么    139 题60:一行以毙之    141 题61:日期游戏    143 题62:名字游戏    145 题63:更多同样的问题  147 题64:按余数编组    149 题65:疑似排序的惊人传奇  152 第8 章更多类之    157 题66:一件私事    157 题67:对字符串上瘾    161 题68:灰色的阴影    163 题69:黑色的渐隐    165 题70:一揽子交易    167 题71:进口税    169 题72:终极危难    171 题73:隐私在公开    173 题74:同一性的危机    175 题75:头还是尾?     177 名字重用的术语    180 第9 章更多库之    183 题76:乒乓    183 题77:乱锁之妖    185 题78:反射的影响    189 题79:狗狗的幸福生活  193 题80:更深层的反射    195 题81:无法识别的字符化  197 题82:啤酒爆炸    199 题83:诵读困难者的一神论  201 题84:戛然而止    203 题85:延迟初始化  205 第10 章高级题    209 题86:有害的括号垃圾  209 题87:紧张的关系  211 题88:原始类型的处理  213 题89:泛型迷药  217 题90:荒谬痛苦的超类  221 题91:序列杀手  224 题92:双绞线  229 题93:类的战争  231 题94:迷失在混乱中  233 题95:来份甜点  237

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值