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运算符的详解?下面希望有你要的答案,我们一起来看看吧!

java运算符的详解(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 */

下面是合理使用的规则:

  1. 仅限单 _,不能多条相连。
  2. 数值开头和结尾不允许出现 _。
  3. F、D 和 L的前后禁止出现 _。
  4. 二进制前导 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 没有的。

如果移动 charbyteshort,则会在移动发生之前将其提升为 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 的基本数据类型(即 charbyteshort)执行任何算术或按位操作,这些值会在执行操作之前类型提升为 int,并且结果值的类型为 int。若想重新使用较小的类型,必须使用强制转换(由于重新分配回一个较小的类型,结果可能会丢失精度)。通常,表达式中最大的数据类型是决定表达式结果的数据类型。float 型和 double 型相乘,结果是 double 型的;intlong 相加,结果是 long 型。

截断和舍入

floatdouble 转换为整数值时,小数位将被截断。若你想对结果进行四舍五入,可以使用 java.lang.Math 的 round() 方法:

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页