百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

《Java编程思想》第五版:第四章 运算符

xsobi 2024-11-23 10:51 1 浏览

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
public class Equivalence {
   public static void main(String[] args) {
       Integer n1 = 47;
       Integer n2 = 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)和 !)根据参数的逻辑关系生成布尔值 truefalse

但是 请注意,如果在预期为 String 类型的位置使用 boolean 类型的值,则结果会自动转为适当的文本格式(即 "true" 或 "false" 字符串)。

逻辑运算符支持一种称为“短路”(short-circuiting)的现象。整个表达式会在运算到可以明确结果时就停止并返回结果,这意味着该逻辑表达式的后半部分不会被执行到。

字面常量值

通常,当我们向程序中插入一个字面值常量(Literal)时,编译器会确切地识别它的类型。当类型不明确时,必须辅以字面值常量关联来帮助编译器识别。

在文本值的后面添加字符可以让编译器识别该文本值的类型。对于 Long 型数值,结尾使用大写 L 或小写 l 皆可(不推荐使用 l,因为容易与阿拉伯数值 1 混淆)。大写 F 或小写 f 表示 float 浮点数。大写 D 或小写 d 表示 double 双精度。

       int i1 = 0x2f; // 16进制 (小写)
       int i2 = 0X2F; // 16进制 (大写)
       int i3 = 0177; // 8进制 (前导0)
       char c = 0xffff; // 最大 char 型16进制值
       byte b = 0x7f; // 最大 byte 型16进制值 01111111;
       short s = 0x7fff; // 最大 short 型16进制值
       long n1 = 200L; // long 型后缀
       long n2 = 200l; // long 型后缀 (容易与数值1混淆)
       long n3 = 200;
       byte blb = (byte)0b00110101;
       short bls = (short)0B0010111110101111;
       int bli = 0b00101111101011111010111110101111;
       long bll = 0b00101111101011111010111110101111;
       float f1 = 1;
       float f2 = 1F; // float 型后缀
       float f3 = 1f; // float 型后缀
       double d1 = 1d; // double 型后缀
       double d2 = 1D; // double 型后缀

十六进制(以 16 为基数),适用于所有整型数据类型,由前导 0x0X 表示,后跟 0-9 或 a-f (大写或小写)。

八进制(以 8 为基数)由 0~7 之间的数字和前导零 0 表示。

Java 7 引入了二进制的字面值常量,由前导 0b0B 表示,它可以初始化所有的整数类型。

下划线

Java 7 中有一个深思熟虑的补充:我们可以在数字字面量中包含下划线 _,以使结果更清晰。这对于大数值的分组特别有用。代码示例:

double d = 341_435_936.445_667;
       System.out.println(d);
       int bin = 0b0010_1111_1010_1111_1010_1111_1010_1111;
       System.out.println(Integer.toBinaryString(bin));
       System.out.printf("%x%n", bin); // [1]
       long hex = 0x7f_e9_b7_aa;
       System.out.printf("%x%n", hex);
/***********输出结果***********/
/*
3.41435936445667E8
101111101011111010111110101111
2fafafaf
7fe9b7aa
*/

下面是合理使用的规则:

  1. 仅限单 _,不能多条相连。
  2. 数值开头和结尾不允许出现 _
  3. FDL的前后禁止出现 _
  4. 二进制前导 b 和 十六进制 x 前后禁止出现 _

指数计数法

// 大写 E 和小写 e 的效果相同:
       float expFloat = 1.39e-43f;
       expFloat = 1.39E-43f;
       System.out.println(expFloat);
       double expDouble = 47e47d; // 'd' 是可选的
       double expDouble2 = 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.Mathround() 方法:

相关推荐

js向对象中添加元素(对象,数组) js对象里面添加元素

一、添加一个元素对象名["属性名"]=值(值:可以是一个值,可以是一个对象,也可以是一个数组)这样添加进去的元素,就是一个值或对象或数组...

JS小技巧,如何去重对象数组?(一)

大家好,关于数组对象去重的业务场景,想必大家都遇到过类似的需求吧,这对这样的需求你是怎么做的呢。下面我就先和大家分享下如果是基于对象的1个属性是怎么去重实现的。方法一:使用.filter()和....

「C/C++」之数组、vector对象和array对象的比较

数组学习过C语言的,对数组应该都不会陌生,于是这里就不再对数组进行展开介绍。模板类vector模板类vector类似于string,也是一种动态数组。能够在运行阶段设置vector对象的长度,可以在末...

如何用sessionStorage保存对象和数组

背景:在工作中,我将[{},{}]对象数组形式,存储到sessionStorage,然后ta变成了我看不懂的形式,然后我想取之用之,发现不可能了~记录这次深刻的教训。$clickCouponIndex...

JavaScript Array 对象 javascript的array对象

Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...

JavaScript中的数组Array(对象) js array数组

1:数组Array:-数组也是一个对象-数组也是用来存储数据的-和object不同,数组中可以存储一组有序的数据,-数组中存储的数据我们称其为元素(element)-数组中的每一个元素都有一...

数组和对象方法&amp;数组去重 数组去重的5种方法前端

列举一下JavaScript数组和对象有哪些原生方法?数组:arr.concat(arr1,arr2,arrn);--合并两个或多个数组。此方法不会修改原有数组,而是返回一个新数组...

C++ 类如何定义对象数组?初始化数组?linux C++第43讲

对象数组学过C语言的读者对数组的概念应该很熟悉了。数组的元素可以是int类型的变量,例如int...

ElasticSearch第六篇:复合数据类型-数组,对象

在ElasticSearch中,使用JSON结构来存储数据,一个Key/Value对是JSON的一个字段,而Value可以是基础数据类型,也可以是数组,文档(也叫对象),或文档数组,因此,每个JSON...

第58条:区分数组对象和类数组对象

示例设想有两个不同类的API。第一个是位向量:有序的位集合varbits=newBitVector;bits.enable(4);bits.enable([1,3,8,17]);b...

八皇后问题解法(Common Lisp实现)

如何才能在一张国际象棋的棋盘上摆上八个皇后而不致使她们互相威胁呢?这个著名的问题可以方便地通过一种树搜索方法来解决。首先,我们需要写一个函数来判断棋盘上的两个皇后是否互相威协。在国际象棋中,皇后可以沿...

visual lisp修改颜色的模板函数 怎么更改visual studio的配色

(defunBF-yansemokuai(tuyuanyanse/ss)...

用中望CAD加载LISP程序技巧 中望cad2015怎么加载燕秀

1、首先请加载lisp程序,加载方法如下:在菜单栏选择工具——加载应用程序——添加,选择lisp程序然后加载,然后选择添加到启动组。2、然后是添加自定义栏以及图标,方法如下(以...

图的深度优先搜索和广度优先搜索(Common Lisp实现)

为了便于描述,本文中的图指的是下图所示的无向图。搜索指:搜索从S到F的一条路径。若存在,则以表的形式返回路径;若不存在,则返回nil。...

两个有助于理解Common Lisp宏的例子

在Lisp中,函数和数据具有相同的形式。这是Lisp语言的一个重大特色。一个Lisp函数可以分析另一个Lisp函数;甚至可以和另一个Lisp函数组成一个整体,并加以利用。Lisp的宏,是实现上述特色的...