Think in Java (5th)On Java 8 系列:第5版Java编程思想,基于java8,由于第4版是基于java5,中间有很多变化,作者 [美] Bruce Eckel 更新了这一java入()quan)门(tui)指南,本书只有电子版,可在github上找到中文翻译版:https://github.com/LingCoder/OnJava8,我来为大家科普一下关于java运算符的详解?下面希望有你要的答案,我们一起来看看吧!
java运算符的详解
Think in Java (5th)On Java 8 系列:第5版Java编程思想,基于java8,由于第4版是基于java5,中间有很多变化,作者 [美] Bruce Eckel 更新了这一java入()quan)门(tui)指南,本书只有电子版,可在github上找到中文翻译版:https://github.com/LingCoder/OnJava8
这里只记录平时用的较少、比较冷门的知识点、或者非常非常重要的知识点做记录。
Java 是从 C 的基础上做了一些改进和简化发展而成的。
几乎所有运算符都只能操作基本类型(Primitives)。唯一的例外是 =、== 和 !=,它们能操作所有对象(这也是令人混淆的一个地方)。除此以外,String 类支持 和 =。
赋值
基本类型的赋值都是直接的,而不像对象,赋予的只是其内存的引用。
a = b ,如果 b 是基本类型,那么赋值操作会将 b 的值复制一份给变量 a, 此后若 a 的值发生改变是不会影响到 b 的。
如果是为对象赋值,当对一个对象进行操作时,我们实际上操作的是它的引用。所以我们将右边的对象赋予给左边时,赋予的只是该对象的引用。此时,两者指向的堆中的对象还是同一个。 改变a 也就改变了 b。这是因为 a 和 b 此时指向的是堆中同一个对象。(a 原始对象的引用在 b 赋值给其时丢失,它引用的对象会在垃圾回收时被清理),这种现象通常称为别名(aliasing)
但是假若你不想出现这里的别名引起混淆的话,你可以
a.name=b.name;
这样做保留了两个单独的对象, 而不是丢弃一个并将 a 和 b 绑定到同一个对象。
方法传参:当你将引用传递给方法时,它仍指向同一对象。
a=b=c=1;
算术运算符 包括加号 、减号 -、除号 /、乘号 * 以及取模 %(从整数除法中获得余数)。整数除法会直接砍掉小数,而不是进位。
一元减号可以得到数据的负值。一元加号的作用相反,不过它唯一能影响的就是把较小的数值类型自动转换为 int 类型。
递增和递减
递增 和递减 --,意为“增加或减少一个单位。
“前递增”表示 运算符位于变量或表达式的前面;而“后递增”表示 运算符位于变量的后面, 递减同理。前缀时会先执行递增/减运算,再返回值。后缀时会先返回值,再执行递增/减运算。
前递增就是先加,后递增就是后加
关系运算符
关系运算符包括小于 <,大于 >,小于或等于 <=,大于或等于 >=,等于 == 和不等于 !=。
== 和 != 比较的是对象引用
// operators/Equivalence.java
publicclassEquivalence{
publicstaticvoidmain(String[]args) {
Integern1=47;
Integern2=47;
System.out.println(n1==n2);
System.out.println(n1!=n2);
}
}
//sout: true / false
因为 Integer 内部维护着一个 IntegerCache 的缓存,默认缓存范围是 [-128, 127],所以 [-128, 127] 之间的值用 == 和 != 比较也能能到正确的结果
如果47换成128,那么就会输出 false/true
实际使用时要用覆写后的 equals()方法进行比较 :equals() 的默认行为是比较对象的引用而非具体内容。因此,除非你在新类中覆写 equals() 方法,否则我们将获取不到想要的结果。好在大多数 Java 库类通过覆写 equals() 方法比较对象的内容而不是其引用。
逻辑运算符
每个逻辑运算符 && (AND)、||(OR)和 !(非)根据参数的逻辑关系生成布尔值 true 或 false。
但是 请注意,如果在预期为 String 类型的位置使用 boolean 类型的值,则结果会自动转为适当的文本格式(即 "true" 或 "false" 字符串)。
逻辑运算符支持一种称为“短路”(short-circuiting)的现象。整个表达式会在运算到可以明确结果时就停止并返回结果,这意味着该逻辑表达式的后半部分不会被执行到。
字面常量值
通常,当我们向程序中插入一个字面值常量(Literal)时,编译器会确切地识别它的类型。当类型不明确时,必须辅以字面值常量关联来帮助编译器识别。
在文本值的后面添加字符可以让编译器识别该文本值的类型。对于 Long 型数值,结尾使用大写 L 或小写 l 皆可(不推荐使用 l,因为容易与阿拉伯数值 1 混淆)。大写 F 或小写 f 表示 float 浮点数。大写 D 或小写 d 表示 double 双精度。
inti1=0x2f;// 16进制 (小写)
inti2=0X2F;// 16进制 (大写)
inti3=0177;// 8进制 (前导0)
charc=0xffff;// 最大 char 型16进制值
byteb=0x7f;// 最大 byte 型16进制值 01111111;
shorts=0x7fff;// 最大 short 型16进制值
longn1=200L;// long 型后缀
longn2=200l;// long 型后缀 (容易与数值1混淆)
longn3=200;
byteblb=(byte)0b00110101;
shortbls=(short)0B0010111110101111;
intbli=0b00101111101011111010111110101111;
longbll=0b00101111101011111010111110101111;
floatf1=1;
floatf2=1F;// float 型后缀
floatf3=1f;// float 型后缀
doubled1=1d;// double 型后缀
doubled2=1D;// double 型后缀
十六进制(以 16 为基数),适用于所有整型数据类型,由前导 0x 或 0X 表示,后跟 0-9 或 a-f (大写或小写)。
八进制(以 8 为基数)由 0~7 之间的数字和前导零 0 表示。
Java 7 引入了二进制的字面值常量,由前导 0b 或 0B 表示,它可以初始化所有的整数类型。
下划线
Java 7 中有一个深思熟虑的补充:我们可以在数字字面量中包含下划线 _,以使结果更清晰。这对于大数值的分组特别有用。代码示例:
doubled=341_435_936.445_667;
System.out.println(d);
intbin=0b0010_1111_1010_1111_1010_1111_1010_1111;
System.out.println(Integer.toBinaryString(bin));
System.out.printf("%x%n",bin);// [1]
longhex=0x7f_e9_b7_aa;
System.out.printf("%x%n",hex);
/***********输出结果***********/
/*
3.41435936445667E8
101111101011111010111110101111
2fafafaf
7fe9b7aa
*/
下面是合理使用的规则:
- 仅限单 _,不能多条相连。
- 数值开头和结尾不允许出现 _。
- F、D 和 L的前后禁止出现 _。
- 二进制前导 b 和 十六进制 x 前后禁止出现 _。
指数计数法
// 大写 E 和小写 e 的效果相同:
floatexpFloat=1.39e-43f;
expFloat=1.39E-43f;
System.out.println(expFloat);
doubleexpDouble=47e47d;// 'd' 是可选的
doubleexpDouble2=47e47;// 自动转换为 double
System.out.println(expDouble);
//输出 1.39E-434.7E48
第一行的赋值语句中,因为编译器通常会将指数作为 double 类型来处理,所以假若没有这个后缀字符 f,编译器就会报错,提示我们应该将 double 型转换成 float 型。
位运算符
“与运算符” & :两个输入位都是 1 ,结果才是 1,否则 0
“或运算符” | :至少有一个是 1 ,结果就是 1
“异或运算符” ^ :一个是 1,另一个不是 1 ,结果才是 1
“非运算符” ~ :对1个自变量 取反, 其他所有运算符都是二元运算符)
位运算符和逻辑运算符都使用了同样的字符,只不过数量不同。位短,所以位运算符只有一个字符。位运算符可与等号 = 联合使用以接收结果及赋值:&=,|= 和 ^= 都是合法的(由于 ~ 是一元运算符,所以不可与 = 联合使用)。
我们将 Boolean 类型被视为“单位值”(one-bit value),所以它多少有些独特的地方。我们可以对 boolean 型变量执行与、或、异或运算,但不能执行非运算(大概是为了避免与逻辑“非”混淆)。对于布尔值,位运算符具有与逻辑运算符相同的效果,只是它们不会中途“短路”。
移位运算符
只能用于处理整数类型。
左移位运算符 << 能将其左边的运算对象向左移动右侧指定的位数(在低位补 0) 。
右移位运算符 >> 则相反。 右移位运算符有“正”、“负”值:若值为正,则在高位插入 0;若值为负,则在高位插入 1。
Java 也添加了一种“不分正负”的右移位运算符(>>>),它使用了“零扩展”(zero extension):无论正负,都在高位插入 0。这一运算符是 C/C 没有的。
如果移动 char、byte 或 short,则会在移动发生之前将其提升为 int,结果为 int。仅使用右值(rvalue)的 5 个低阶位。这可以防止我们移动超过 int 范围的位数。若对一个 long 值进行处理,最后得到的结果也是 long。
移位可以与等号 <<= 或 >>= 或 >>>= 组合使用。左值被替换为其移位运算后的值。
三元运算符
三元运算符,也称为条件运算符。与 if-else 不同的是,三元运算符是有返回结果的。
布尔表达式 ? 值 1 : 值 2
若表达式计算为 true,则返回结果 值 1 ;如果表达式的计算为 false,则返回结果 值 2。
字符串运算符
运用 String 时有一些有趣的现象。若表达式以一个 String 类型开头(编译器会自动将双引号 "" 标注的的字符序列转换为字符串),那么后续所有运算对象都必须是字符串。
因为编译器将其分别转换为其字符串形式然后与字符串变量 s 连接。 这种转换与数据的位置无关,只要当中有一条数据是字符串类型,其他非字符串数据都将被转换为字符串形式并连接。 如果需要控制表达式的计算顺序可以使用括号 ()
类型转换 Casting
假设我们为 float 变量赋值一个整数值,计算机会将 int 自动转换成 float。
若将数据类型进行“向下转换”(Narrowing Conversion)的操作(将容量较大的数据类型转换成容量较小的类型),可能会发生信息丢失的危险。 “向上转换”(Widening conversion),则不必进行显式的类型转换,因为较大类型的数据肯定能容纳较小类型的数据,不会造成任何信息的丢失。
我们对小于 int 的基本数据类型(即 char、byte 或 short)执行任何算术或按位操作,这些值会在执行操作之前类型提升为 int,并且结果值的类型为 int。若想重新使用较小的类型,必须使用强制转换(由于重新分配回一个较小的类型,结果可能会丢失精度)。通常,表达式中最大的数据类型是决定表达式结果的数据类型。float 型和 double 型相乘,结果是 double 型的;int 和 long 相加,结果是 long 型。
截断和舍入
从 float 和 double 转换为整数值时,小数位将被截断。若你想对结果进行四舍五入,可以使用 java.lang.Math 的 round() 方法:
,