《编写高质量代码 改善Java程序的151个建议》书摘
例子1:三元操作符的陷阱
1 int i = 80; 2 String str1 = String.valueOf(i < 100 ? 90 : 100); 3 String str2 = String.valueOf(i < 100 ? 90 : 100.0); 4 System.out.println(str1);// 输出:90 5 System.out.println(str2);// 输出:90.0
当你使用三元运算符,两边的操作数的类型不一致的时候,这就涉及到三元操作符的转换规则:
- 若两个操作数不可转换,则不做转换,返回值为Object类型;
- 若两个操作数是明确类型的表达式(比如变量),则按照正常的二进制数字来转换。int类型转换为long类型,long类型转换成float类型;
- 若两个操作数中有一个是数字S,另外一个是表达式,且其类型为T,那么,若数字S在T的范围内,则转换为T类型;若S超过了T的范围,则T转换为S类型;
- 若两个操作数字都是数字。则返回值类型为范围较大者。
例子2:一个关于自增的陷阱
1 int count = 0; 2 for(int i=0; i<=100; i++) { 3 count = count++; 4 } 5 System.out.println("count = " + count);//输出:count = 0
循环体内的“count = count++;”语句第一次执行时的详细处理步骤如下:
- JVM把count值(此时为0)拷贝到临时变量区;
- 将count的值加1(此时为1);
- 返回临时变量区的值(此时为0);
- 将返回值赋值给count(即count被赋值为0)。
用代码来表示则相当于以下语句:
1 public static int mockAdd(int count) { 2 int temp = count; 3 count = count + 1; 4 return temp; 5 }
不过,在C++中,“count = count++”与“count++”是等效的,PHP与Java则一样(不等效)
例子3:如何结合JS脚本处理易变的业务
1 //JS代码 2 var factor; 3 function formula(var1, var2) { 4 return var1 + var2 * factor; 5 }
1 //Java代码 2 int first = 11; 3 int second = 22; 4 String filePath = "D:/test.js"; 5 ScriptEngineManager manager = new ScriptEngineManager(); 6 // 获得一个javascript的执行引擎 7 ScriptEngine engine = manager.getEngineByName("javascript"); 8 // 建立上下文变量 9 Bindings bind = engine.createBindings(); 10 // 为js文件里的某个参数赋值 11 bind.put("factor", 5); 12 // 绑定上下文,作用域是当前引擎范围 13 engine.setBindings(bind, ScriptContext.ENGINE_SCOPE); 14 FileReader fr = new FileReader(filePath); 15 engine.eval(fr);// 执行js代码 16 // 判断是否为可调用的方法 17 if (engine instanceof Invocable) { 18 Invocable invocable = (Invocable) engine; 19 Double result = (Double) invocable.invokeFunction("formula", first, 20 second); 21 System.out.println("运算结果: " + result.intValue()); 22 }
例子5:关于instanceof方法的使用
1 import java.util.Date; 2 3 public class InstanceofDemo { 4 public static void main(String[] args) { 5 System.out.println("Sting" instanceof Object);// 输出:true 6 // 分析:“String"是一个字符串,字符串又继承了Object 7 /***********************************/ 8 9 System.out.println(new String() instanceof String);// 输出:true 10 // 分析:一个类的对象当然是它的实例 11 /***********************************/ 12 13 System.out.println(new Object() instanceof String);// 输出:false 14 // 分析:Object是父类,其对象当然不是String类的实例了。 15 // 需要注意的是,这语句编译通过了,因为只要instanceof关键字的左右两个操作数有继承或实现关系,就可以编译通过 16 /***********************************/ 17 18 System.out.println(null instanceof String);// 输出:false 19 // 分析:instanceof特有的规则:若左操作数是null,结果就直接返回false,不需要判断运算右操作数是什么类,类似短路运算。 20 // 因此,在使用instanceof操作符时,不用关心被判断的类(也就是左操作数)是否为null,这与我们经常用到的equals、toString方法不同。 21 /***********************************/ 22 23 System.out.println((String) null instanceof String);// 输出:false 24 // 分析:不要看这里有个强制类型转换就认为结果是true。因为null是一个万用类型,也可以说它没类型,即使进行类型转换还是个null 25 /***********************************/ 26 27 System.out.println(‘A‘ instanceof Character);// 编译报错 28 // 分析: 29 // 因为‘A‘是一个char类型,也就是一个基本类型,不是一个对象,instanceof只能用于对象的判断,不能用于基本类型的判断,所以编译报错 30 /***********************************/ 31 32 System.out.println(new Date() instanceof String);// 编译报错 33 // 分析:因为Date类与String没有继承或实现关系,所以在编译时直接就报错了,instanceof操作符的左右操作数必须有继承或实现关系,否则会编译不通过 34 /***********************************/ 35 36 System.out.println(new GenericClass<String>().isDateInstance("test"));// 输出:false 37 // 分析:此处T是个String类型,与Date之间没有继承或实现关系,为什么语句"return t instanceof Date"会编译通过呢? 38 // 因为Java的泛型是为编码服务的,在编译成字节码时,T已经是Object类型了,传递的实参是String类型,也就是说T的表面类型是Object,实际类型是String 39 // 所以,语句此处的"return t instanceof Date"语句就等价于"return Object instanceof Date"了 40 } 41 } 42 43 class GenericClass<T> { 44 // 判断是否是Date类型 45 public boolean isDateInstance(T t) { 46 return t instanceof Date; 47 } 48 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。