【Java解惑】表达式问题
1. 如果判断一个参数是否是奇数?
我们通过下面代码来尝试一下,看看方法可行不:
public static boolean isOdd(int i) {
return i % 2 == 1;
} public static void main(String[] args) {
System.out.println(isOdd(8));
}
解惑:
(1)程序看起来是可以的,因为利用表达式 i % 2,计算的是 i 除以2时所产生的余数。但事实上,这种方法是不行的,在四分之一的时间里它返回的都是错误的答案;
(2)因为它对所有的负奇数的判断都会失败,因为当i是一个负奇数时,i % 2等于-1而不是1,因此这种判断方式是不正确的。
而通常正确的做法是这样的:
public static boolean isOdd(int i) {
return i % 2 != 0;
}
只需将 i % 2与0而不是1比较,并且使用想反的比较符即可;
如果在一个强调性能的环境中使用此方法,那么使用位操作符(&)会更好;
public static boolean isOdd(int i) {
return (i & 1) != 0;
}
2. 条件表达式问题
条件表达式,有一个更广泛的名字:问号冒号操作符。我们看以下程序,并考虑以下程序会输出什么内容呢?
public static void main(String[] args) {
char x = 'X';
int i = 0;
System.out.print(true ? x : 0);
System.out.print(false ? i : x);
}
我一开始觉得,第一个打印的是char类型的x的值'X',第二个依旧是char类型的x的值'X',因此程序应该输出两个X。但结果却输出了X88。
答案就在这个条件表达式的第二个和第三个操作数的类型不相同,x是char类型的,而0是int类型的常量,i是int类型的变量。
解惑:
(1)混合类型的计算会引起混乱,而这一点在条件表达式中比在其他任何地方都表现得更明显;
(2)条件表达式的规则很长,很复杂,很难完全记住,但核心就以下三点:
- 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型,那么就可以绕过混合类型的计算来避免大麻烦;
- 如果一个操作数的类型是T,T表示byte、short或char,而另一个操作数是一个int类型的常量表达式,它的值可以用类型T表示,那么条件表达式的类型就是T;
- 否则,将对操作数类型进行二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型;
(3)在本程序的两个表达式中,一个操作数的类型是char,另一个的类型是int。首先,在两个表达式中,int操作数都是0,它是可以被表示成一个char的。然后,只有第一个表达式中的int操作数是常量(0),而第二个表达式中的int操作数是变量(i),因此,第二点被应用到第一个表达式上,返回char,第三点被用到第二个表达式上,返回的是对int和char进行二进制提升之后的类型,即int;
(4)条件表达式的类型将确定调用哪一个重载的print方法,对第一个来说,调用的是PrintStream.print(char),第二个是调用的PrintStream.print(int)。前一个重载方法将变量x的值作为Unicode字符(X)打印,而后一个是将其作为一个十进制整数(88)打印。
(5)还有一种情况,是使用final修饰符用于i的声明,把i转换为一个常量表达式,从而让程序打印XX,但这会引起混乱,不建议使用。
总结:因此,在使用条件表达式时,最好在条件表达式中使用类型相同的第二和第三操作数。
3. 赋值表达式问题
请写两行代码,给出x和i的声明,使得
x += i;
合法,而
x = x + i;
不合法。
这个不太难,我们可以很快的写出来,但重要的是我们要理解这两个赋值表达式。
short x = 1;
int i = 123456;
Java语言规范中讲到:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
即复合赋值 E1 op=E2等价于简单赋值 E1 = (T)((E1) op (E2)),其中T是E1的类型,并且E1只被计算一次。
换句话说,就是复合赋值表达式自动的将所执行的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,那么这个转型不会有任何影响,然而,如果结果的类型范围要比变量类型范围要小的话,如左侧是short类型,变量类型是int类型,那么复合赋值操作符将自动的执行类型转换,并把变量类型的高位给截取掉;
因此,x += i 的结果是一个负值:-7615
总结:
(1)请不要将复合赋值操作符作用于byte、short或char类型的变量上;
(2)在将复合赋值操作符作用于int类型的变量上时,要确保表达式右侧不是long、float或double类型;
(3)同样,作用于float上时,要确保右侧表达式不是double类型。
参考自:《Java解惑》
【Java解惑】表达式问题的更多相关文章
- Java解惑五:类之谜
本文是依据JAVA解惑这本书,做的笔记.电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题46 函数重载的问题. JAVA重载解析过程 ...
- java解惑之常常忘记的事
java解惑之常常忘记的事 2012-10-17 18:38:57| 分类: JAVA | 标签:基础知识 软件开发 |举报|字号 订阅 针对刚接触java的菜鸟来说,java基础知识 ...
- Java Lambda表达式初探
Java Lambda表达式初探 前言 本文受启发于Trisha Gee在JavaOne 2016的主题演讲Refactoring to Java 8. Java 8已经发行两年多,但很多人仍然在使用 ...
- Java Lambda表达式入门
Java Lambda表达式入门 http://blog.csdn.net/renfufei/article/details/24600507 Java 8十个lambda表达式案例 http://w ...
- Java Web表达式注入
原文:http://netsecurity.51cto.com/art/201407/444548.htm 0×00 引言 在2014年6月18日@终极修炼师曾发布这样一条微博: 链接的内容是一个名为 ...
- 利用Java实现表达式二叉树
(*^-^*) 什么是二叉树,这里不再介绍,可以自行百度:二叉树.在这里利用java实现“表达式二叉树”. 表达式二叉树的定义 第一步先要搞懂表达式二叉树是个什么东东?举个栗子,表达式:(a+b×(c ...
- Java Lambda表达式入门[转]
原文链接: Start Using Java Lambda Expressions http://blog.csdn.net/renfufei/article/details/24600507 下载示 ...
- ref:一种新的攻击方法——Java Web表达式注入
ref:https://blog.csdn.net/kk_gods/article/details/51840683 一种新的攻击方法——Java Web表达式注入 2016年07月06日 17:01 ...
- Java Lambda表达式教程与示例
Lambda表达式是Java 8中引入的一个新特性.一个lambda表达式是一个匿名函数,而且这个函数没有名称且不属于任何类.lambda表达式的概念最初是在LISP编程语言中引入的. Java La ...
随机推荐
- [PWA] 2. Service worker life cycle
Once serive worker is registered, the first time we go to the app, we cannot see the logs from servc ...
- Android 模仿QQ空间风格的 UI(转)
本文内容 环境 演示模仿QQ空间风格的UI 虽然这个 UI 跟现在的QQ空间有点差别,但是也能学到很多东西. 下载 Demo 环境 Windows 7 64 位 Eclipse ADT V22.6.2 ...
- android基础篇学习心得
android技术中,线程.进程.JNI.IPC和各个小框架结构是基本功.在跟随高焕堂老师的android程序猿到架构师之路系列视频中 学习完基础篇之后,颇有些心得,记录下来. android开发就是 ...
- 在/etc/password用户名前面加hello,ID前加is
方法2: #!/bin/sh #set -x file=/etc/passwd while read LINE #for i in `cat $file` do #username=`echo $i| ...
- 对SQL Server SQL语句进行优化的10个原则
1.使用索引来更快地遍历表. 缺省情况下建立的索引是非群集索引,但有时它并不是最佳的.在非群集索引下,数据在物理上随机存放在数据页上.合理的索引设计要建立在对各种查询的分析和预测上.一般来说:①.有大 ...
- 【转】 iOS 原生二维码扫描(可限制扫描区域)
在用 AVFoundation 完成扫码后,遇到2个问题: 1,如何限制扫描范围? 2.条形码如何扫描? 一位朋友的文章帮助了我,特地转来,可以帮到有需要的朋友. 原文:http://blog.csd ...
- 网络流转换为Byte数组
/// <summary> /// 网络流转换为Byte数组 /// </summary> /// <param name="stream">& ...
- 高性能IO设计模式之阻塞/非阻塞,同步/异步解析
提到高性能,我想大家都喜欢这个,今天我们就主要来弄明白在高性能的I/O设计中的几个关键概念,做任何事最重要的第一步就是要把概念弄的清晰无误不是么?在这里就是:阻塞,非阻塞,同步,异步. OK, 现在来 ...
- [500lines]500行代码写web server
项目地址:https://github.com/aosabook/500lines/tree/master/web-server.作者是来自Mozilla的Greg Wilson.项目是用py2写成. ...
- Spring4.0学习笔记(7) —— 通过FactoryBean配置Bean
1.实现Spring 提供的FactoryBean接口 package com.spring.facoryBean; import org.springframework.beans.factory. ...