java 代码的基本结构

从上一章内容中我们已经书写了一个基本结构:

  1. public class Test {
  2. public static void main(String[] args){
  3. // main 函数中书写各项指令
  4. System.out.println("this is a test");
  5. }
  6. }

java 源代码中能出现的单词称为“词法单元” 或 “Token”,从 java 语言基本结构可以看出:

  1. 每个 java 文件都必须书写一个 java 类 public class 类名{} 且类名和文件名一致
  2. 在可直接运行的 java 类中,拥有一个叫 main() 的主方法,作为程序的主入口

还可以看出 java 代码其中包含的要素:

  • 一些英文单词
  • 3 种括号
  • 点操作符
  • 双引号
  • 分号

同人类的语言拥有字母、单词、语句、文章类似,编程语言也是由符号、标识符、指令组成,所以不必把编程语言想象过于神话。有了字母可以组词,多个词语又可以组成文。只是在编程语言中,词语不被叫作“单词”,而是被叫作标识符。

如果将英文和编程语言对应起来就应该是:

  • 字母 —— 符号
  • 单词 —— 标识符
  • 语句 —— 指令
  • 文章 —— 程序

    标识符与关键字

标识符其就是打上标记帮助识别的符号。在书写标识符时,也有命名规范,就好比给中国人上户口不能用英语名称、数字、违法乱纪的敏感文字词语是一样的,得讲究“规矩规范”。

空白符和注释

有意思的是 java 是一种格式自由的语言,不用遵循特定的缩进格式,不过在每个 Token 间必须出现至少一个空白符,空格键、制表符、换行、换页都可以。不过使用编辑器一个格式化快捷键能把一切都搞定不过多赘述。

注释

注释的作用不过多赘述,主要提到 java 中的三种注释:

  1. 单行注释 //
  2. 多行注释 /**/
  3. 文档注释

单行注释很明显一次注释一行代码了,多行注释也被称为块注释,可以在任何地方出现,甚至是和它要解释的语句放在同一行。

  1. /*
  2. 这是一个多行注释,
  3. 编译器在编译时会忽略掉它
  4. */
  5. public class /* 这是类声明 */ HelloWorld {
  6. /* 这是程序的入口点 */
  7. public static void main(String[] /* 方法的参数 */ args) {
  8. System.out.println("Hello, World!"); /* 在控制台上打印一条消息 */
  9. }
  10. }

这里,在/**/ 之间的所有内容都会被编译器忽略掉,所以不会影响程序的执行。当然,在语句之间使用注释必然会影响代码的可读性,一般不推荐这样做。
必须要注意的是,多行注释不能嵌套。比如,如下代码试图在一个多行注释中嵌入另一个多行注释。但是,第一个 /* 总是会找离它最近的 */ 来搭配,于是最后一个 */ 就成了非法 Token,导致代码不能通过编译。
文档注释是 Java 中的一种特殊注释,主要用于生成 API 帮助文档,提供给 API 的用户参考。写好代码以及文档注释后,我们可以使用 JDK 中附带的 Javadoc 工具,从程序源代码中抽取类、方法、成员等注释,形成一个和源代码配套的 API 帮助文档。也就是说,只要在编写程序时以一套特定的标签作注释,在程序编写完成后,就可以用 Javadoc 同时生成程序的开发文档了。
文档注释是以 /** 为开始符号,以 */ 为结尾符号,中间放上文档注释的内容:

  1. /** 这是个文档注释 */
  2. /**
  3. 这也是一个
  4. 文档注释
  5. */
  6. /**
  7. * 这是一个更好看的文档注释
  8. * 星号不会影响文档
  9. */

文档注释中可以加入一些特殊标签,这些标签一般以 @ 开头,后跟一个指定的名字。有些标签是以 {@ 开头,以 } 结束。javadoc 可以识别出这些标签。这些标签有十几种,下面我们只列出来几种常见的:

  • @author:标识一个类的作者,一般用于类注释。格式为:@author 描述
  • @version:说明乐利的版本,一般用于类注释。格式为:@version 版本信息
  • @param:说明方法的参数,一般用于方法注释。格式为:@param 参数名 解释
  • @return:说明返回值类型,一般用于方法注释。格式为:@return 解释

必须要注意的是:文档注释只放在类、接口、成员变量、方法之前,因为 Javadoc 只处理这些地方的文档注释,其它地方的文档注释会被 javadoc 忽略。
如下所示的 JavadocDemo 程序中,就在类和方法之前使用了文档注释。此外,在 main()方法中也添加了文档注释,但是这条注释会被 javadoc 忽略,不会出现在生成的 API 文档中。

  1. /**
  2. * @author Atian
  3. * @version jdk17
  4. */
  5. public class Hello {
  6. /**
  7. * @param str 接受一个字符串为参数
  8. */
  9. public void sayHello(String str) {
  10. /**
  11. * 输出一条消息
  12. */
  13. System.out.println("Hello, " + str);
  14. }
  15. }

写好代码后,怎么看 API 文档呢?有三种方式:

  • 1)在命令行提示符下,用 javadoc 工具生成(不推荐)
  • 2)在 IDEA 下,点击 Tools -> Generate javaDoc...,打开生成 JavaDoc 的对话框(注意:中文文档的 Locale 设置为 zh_CN,命令行参数设置为 -encoding UTF-8 -charset UTF-8,这样才不会乱码),生成 API 文档。然后在浏览器中查看

    命名规范

对于编程语言自定义标识符的命名规范可被分为两大类:

  • 硬性要求
  • 软性要求

硬性要求则是指必须遵守否则无法通过编译的:

  1. 命名可以包含数字、字母、下划线、$
  2. 数字不可作为开头
  3. 大小写敏感

除此以外还有一些软性要求是作为开发人员们约定俗成的行规:

  1. 首当其冲的就是给标识符取名得见名知意,便于阅读和理解代码,特别要谨慎使用缩写,遵守程序界的公共规范
  2. 类名使用帕斯卡命名法,首字母大写
  3. 变量名小写,当有多个单词组合成变量名,则使用驼峰命名法 chineseNewYear
  4. 常量(不可变的量)名,使用全大写 GENDER
  5. 包名、工程名全小写
  6. 方法名与变量名的要求一致,但应当从方法名体现其功能,通常为动词或动宾短语

标识符分类

标识符可以分为两大类:

  1. 语言已经预定义好的、被这项语言系统占用、有特定含义不可再用于其他地方的称为“关键字”
  2. 用户自定义
    • 在使用别人已经定义好的 API 时必须保持定义者定义的名字
    • 当前开发人员自定义的类、数据量、方法等

像在代码段中,除了类名 Test 和 args 可以另外修改名称外,其余的都是关键字,不可被更改:

  1. public class Test {
  2. public static void main(String[] args){
  3. // main 函数中书写各项指令
  4. System.out.println("this is a test");
  5. }
  6. }

关于类的其他一些细节点:

  1. 所有代码都要写在类的 {} 中
  2. 如果这个类的访问修饰符是 public 的那么类名必须和文件名一致
  3. 一个 java 文件可以书写多个类,但通常不这么做。public 的只能有一个
  4. 一个类里只能有一个 main()
  5. 编译后的 .class 字节码文件数量和 java 文件中定义的类的数量有关,换句话说,一个类就有一个 .class 文件

数据类型

十进制二进制转换工具
八进制十进制转换工具

提到数据类型首先需要提到 计算机中的存储单位。

存储单位在日常生活中购买手机、电脑、内存卡也常被提到。它其实就是一种计量单位,在计算机内部,信息都是釆用二进制的形式进行存储、运算、处理和传输的。在计算机各种存储介质(如内存条、硬盘、光盘等)的存储容量表示中,用户所接触到的存储单位常见的容量单位就包含了 KB、MB、GB 和 TB。

由于计算机中只能识别 0 和 1,所以在计算机中能单独存放 “0” 或 “1” 的一个空间作为最小存储单位,称为“位”,bit。假设当前需要存放 2,十进制数字 2 在二进制的机器语言里被记作 10(一零),那就需要 2 个位来存放。

但这个单元实在是太小了,我们在实操当中往往不会以最小位来操作,而是操作由 8 个位组成的 “字节”。字节越多,能表示的范围就更大了,像 KB、MB、GB 甚至于 TB。

  • 1Byte = 8 bit
  • 1 KB = 1024 Byte
  • 1 MB = 1024 KB
  • 1 GB = 1024 MB
  • 1 TB = 1024 GB

从换算表里好像老出现了 1024,那为什么是 1024 呢?因为 2^10=1024 才是程序员所“认为”的整数。

数据类型的作用

编程语言设计使用数据类型,其原因就包含了两点:

  1. 告知计算机使用哪种方式完成数据量的二进制转换。整数、实数、字符串等其转换方式各不相同
  2. 计算机会确定为该类型的数据分配多大的、适合的内存空间,以免造成内存浪费或空间不够

作为一个开发人员而言,一定要有数据类型的敏感度,在编码过程中,所有数据都带着数据类型的特性参与一切运算和操作,会直接影响执行的效率和效果,这种敏感度应该是开发人员的基本素质。

数据类型的分类

java 中数据类型可分为两大类:

  1. 基本数据类型,4 类 8 种
    • 整型(共 4 种)Byte、short、int 、long
    • 浮点型
    • 字符型
    • 布尔型
  2. 引用数据类型
    • 代表复杂数据类型,包含但不仅包含类、数组、接口等等

本章只提到基本数据类型。

基本数据类型

整型

java 的整数类型共有 4 种:

  1. byte 1个字节
  2. short 2个字节
  3. int 4个字节(默认)
  4. long 8个字节 | 类型 | 关键字 | 所占空间 | 范围 | | —- | —- | —- | —- | | 字节型 | byte | 1 个字节 | -2^7 ~2^7-1
    -128 ~ 127 | | 短整型 | short | 2个字节 | -2^15 ~ 2^15-1 | | 整型 | int(默认) | 4个字节 | -2^31 ~ 2^31-1 | | 长整型 | Long | 8个字节 | -2^63 ~ 2^63-1 |

这 4 个关键字都是定义整型,字节数越大,能够存放的数字范围就越大。当然,但也并不是说选择的类型字节数越大越好,而是应该在开发过程中选取最合适的。从编程经验看来呢,整数 intlong 使用得是最多的,所以往往在定义数据类型时,使用 int 通常不会出错,满足常规所有情况,从所占字节数看来也不算浪费。。

  1. System.out.println(886);

没啥太大用处的 tips

一个没啥用的小 tips:如果整数字面量太长,其可读性就会受到影响。因此,从 java 7 开始,可以用下划线分隔整数字面量中的数字。比如:

  1. int a = 1000000000;
  2. int a = 10_0000_0000;

整数字面量可以写成十进制、十六进制、八进制或者二进制。

  • 十六进制整数字面量是在整数的十六进制表示前面加前缀 0X 或者 0x。比如,如下代码把十六进制整数 2E(十进制整数 46) 赋值给 byte 类型变量 abyte a = 0x2E;
  • 八进制整数字面量是在整数的八进制表示前面加前缀 0。比如,如下代码把八进制整数 123(十进制整数 83)赋值给 byte 类型变量 abyte a = 0123;
  • 二进制整数字面量是在整数的二进制表示前面加 0B 或者 0b。比如,如下代码把二进制整数 010111(十进制整数 23)赋值给 byte 类型变量 abyte a = 0B010111;

    浮点型

java 的浮点类型共有 2 种:

  1. float 4 个字节
  2. double 8个字节(默认) | 类型 | 关键字 | 所占空间 | 范围 | | —- | —- | —- | —- | | 单精度浮点数 | float | 4个字节 | 1.4013E-45 ~ 3.4028E+38 | | 双精度浮点数 | double(默认) | 8个字节 | 4.9E-324 ~ 1.7977E+308 |

float 能保证小数点后 7 位数有效,double 从名称上就可以看出“翻倍”,即能保证小数点后 16 位有效。

字节数越大,能够存放的数字范围越大、精度越高。小数部分的二进制转换有无限除不尽的可能性,所以实数类型在计算机中,天生存在精度问题。实数类型的二进制存放是根据指数形式存放,所以 float 能比 long 存放更大范围。

  1. System.out.println(3.5);

字符型

字符型只有 1 种 char 专用于表示字符型,所占空间是 2 个字节。
字符不仅仅是单指字母 abc,能在键盘上打得出来的都算作字符。字符类型在底层是按照字符编码集的对应以数字形式转换为二进制存放的。所以我们在去记忆的时候,仅需要记住在美国标准信息交换标准码(American Standard Code for Information Interchange, ASCII )大写字母 A 对应 65,小写字母 a 对应 97 再以此类推,对应大小写间相差 32。
中文也有自己的码表,比如说像国标码 GBK,都是在 ASCII 码表的基础上衍生出来的,还有包含了东方文字的 UTF 码等等。
在编程中,我们会将字符编码统一,以免造成编码表与编码表之间编号不同,导致“乱码”。
'A' 就属于一个字符,但 ‘AB’ 就不属于字符 char 基本数据类型了,而是属于引用数据类型要使用双引号 "AB" 了。

  1. System.out.println('a'); // 单引号 System.out.println('AB'); 报错,属于字符串,引用类型
  2. System.out.println("AB");
  3. System.out.println('嘿');
  4. System.out.println('\n'); // 转义 表示换行

字符字面量还可以使用转义序列表示无法用键盘输入的特殊字符。常用转义字符包括:

  • ‘\b’:退格符
  • ‘\t’:Tab 字符
  • ‘\’:反斜线
  • ‘’’:单引号
  • ‘“‘:双引号
  • ‘\n’:换行符
  • ‘\r’:回车键

补充知识- 字符集与字符编码

  • 字符集(Charset):各种语言中支持的所有文字和符号的集合。
  • 字符编码(Character Encoding):字符集在计算机中实现的方式。每一种字符集都有对应的字符编码规则。
  • 码点(Code Point):在某个字符集中,根据某种编码规则将字符编码后得到的值。表示一个字符在字符集中的位置。
  • 通俗的解释:字符集就是把字符放到一起的一个集合。这个集合的每一个字符都对应一个数字,叫做码点。这样就建立起来数字和字符之间的索引关系。某个字符在计算机中怎么表示,具体占用几个字节等等,这些就需要编码规则来解决了。这就是字符编码,它来解决根据某个规则来将字符映射到相应的码点上面。
  • 常见字符集及其字符编码方式
    • ASCII:表示英语及欧洲国家字符。编码方式:
      • 标准ASCII:用1个字节7位二进制表示128个字符。
      • 扩展ASCII:用1个字节表示256个字符(加入部分欧洲字符)。
    • Unicode:表示全世界大多数语言中的字符。Java 支持 Unicode 字符集。更多信息请参考官方网站www.unicode.org。字符编码方式:
      • UTF-32:每个字符都用4个字节表示。
      • UTF-16:每个字符用2或者4个字节表示。
      • UTF-8:每个字符用1到4个字节表示,根据不同的符号而变化字节长度(变长)。互联网上使用最广的一种 Unicode 字符编码方式。编码规则:
        • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的Unicode码。因此,对于英语字母,UTF-8 和 ASCII码是相同的。
        • 对于N字节的符号(N>1),第一个字节的前N位都设为1,第N+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的Unicode码。

布尔型

boolean 类型专用于表示逻辑状态,即 yes or no,true or false。所占大小不固定,JVM 会根据情况自动去分配 1 位或 1 个字节。
在编码过程中通常需要根据某些情况指定程序做相对应的指令,或者是程序会根据指令返回的结果给开发人员,都会去使用到布尔值。

  1. System.out.println(true);
  2. System.out.println(false);

引用数据类型

除 java API 自带的以外,还可以自定义,数量无限制,目前会使用到 String,使用双引号 “” 表示。注意区分字符和字符串。

  1. System.out.println("hello");

变量

拥有了数据类型,我们就能够使用声明指令在内存中申请划分一块空间来存放对应的数据以便获取该数据再进行其他操作。内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。数据值允许在程序运算过程中发生改变。

语法:数据类型 变量名;

  • 声明后赋值称为变量的初始化
  • 赋给变量的值必须与数据类型匹配
  • 跟 javascript 这个弱类型语言的不同之处在于,在 java 中,若一个变量只声明没有赋值就被使用,是不允许被使用的,会报错 可能尚未初始化变量。所以在 java 语言中,变量必须声明+初始化值
  • 同样也存在作用域的限制
  1. /* 声明一个整型 */
  2. int number; // 告诉计算机,声明一个长度为 4 个字节的整型变量名字叫作 number
  3. number = 5; // 将数据 5 放进变量 number 中
  4. /* 声明一个小数 */
  5. double pi = 3.14; // 声明一个 double 类型的变量 pi 赋值为 3.14
  6. /* 声明一个字符 */
  7. char str = 'a'; // char 字符型要使用单引号,一个 char 只能放入一个字符,不能写作 char str = 'ab'
  8. /* 声明一个布尔值 */
  9. boolean flag = true;
  10. flag = false; // 变量即可变的量,初始为 true 可以被改为 false
  11. /* 同时声明多个同类型变量,以逗号分隔 */
  12. int number1 = 1, number2 = 5, number3 = 10;

变量类型与值类型不同的情况,小值可以放进大数据类型的变量中:

  1. Byte b = 1234567890; // 报错 Byte 的字节大小<int 字节大小
  2. long l = 4; // 允许

在 JDK 10+ 新增局部变量 类型推断,允许使用 var 代替变量声明中的数据类型。

  • 使用 var 声明变量必须声明后马上赋值
  • 用 var 只能用于方法内部的局部变量
  • 类型推断是语法糖,编译器在编译后的字节码文件中还是编译成了推断后的类型名字

    1. int age = 18;
    2. var money = 500;

    变量在内存中的存放形式

  • 基本数据类型变量:值直接存在在变量本身定义的空间中

  • 引用数据类型变量:值存放在单独空间,变量空间中存放的是一个引用指向变量值所在的空间位置

    常量

常量,本质上来说是在计算机运行时不会被计算机修改的值。常量分两种:

  1. 字面常量
  2. 符号常量

字面常量

来从一些代码中认识字面常量,只关注赋值符号右侧的值

  1. int number = 20; // “20”就是一个字面常量。论谁来认都是 20
  2. double pi = 3.14; // 3.14 就是类型为 double 的常量
  3. float f = 1.5f; // float 类型的常量 1.5
  4. boolean flag = true; // 布尔类型就只有 true 和 false 两种字符常量了
  5. char str = 'a'; // char 常量必须使用单引号表示,并且只能存放一个字符

区分字符和字符串,字符串常量使用关键字 String + 双引号""去声明:

  1. String s = "hello";

计算机看到具体的数字 20、double 类型的常量、float 类型的常量等,计算机会自动根据类型转二进制,分配存储空间。

符号常量

符号常量其实就是给字面常量取名字,类似于给圆周率取名叫做 PI。常量名称字母全大写,出现多个单词,使用下划线分隔 STUDENT_GENDER,且常量值不可被更改、声明后立即赋值
语法,使用 final 关键字:

  1. final 数据类型 常量名 = 字面常量值;

假设当前想要使用圆周率:

  1. final double PI = 3.1415926;

一旦将业务含义带入到常量值中,声明好这个常量,那么在使用中就都可以使用 PI 去表示 3.1415926 而不用每次用每次写了,方便了许多。 未来在修改常量值时,也只需要修改一处值,就能应用到全局。

运算符

数据量有了以后就可以对数据量进行运算操作得到结果,基于操作数的数量,可以把运算符分为三种类型:

  • 一元运算符:只有一个操作数。一元运算符可以是作为操作数的前缀(比如,++i),也可以是作为操作数的后缀(比如,i++)。
  • 二元运算符:有两个操作数。二元运算符一般采用中置表示法,放在两个操作数之间(比如, 4 + 6)。
  • 三元运算符:有三个操作数。三元运算符也是采用中置表示法,运算符放在三个操作数之间(比如,(age < 18) ? "Childen" : "adult")。

    算数运算符

表达式由运算符和操作数(变量常量皆可)组成,最终会有一个运算结果。包含 +、-、*、/、%
其中 + 号前后的任意操作数是字符串时 + 号作为字符串拼接。

  1. // 注意各数据类型
  2. int a = 5, b = 6, sum = a + b;
  3. System.out.println(sum); // 11
  4. int a = 5, b = '6', sum = a + b;
  5. System.out.println(sum); // 59 '6' 作为了字符,数字 6 在 ASCII 表中编号为 54,等于作了 5+54
  6. int a = 5;
  7. String b = "A";
  8. String c = a + b;
  9. System.out.println(sum); // 5A

% 中余数的正负号只跟被除数有关,被除数是正数余数就是正,被除数是负数余数就是负数。取余仅在整数运算下才有意义。

  1. int a = 10, b = 3, c = a % b;
  2. System.out.println(c); // 1
  3. int a = -10, b = 3, c = a % b;
  4. System.out.println(c); // -1
  5. int a = 10, b = -3, c = a % b;
  6. System.out.println(c); // 1

所有算数运算符号如果两端的运算数是同数据类型那么结果就是该类型的结果。不一致那么运算结果是大数据类型的结果。

【类型提升】 算术运算符可能会造成操作数的类型自动提升到更宽的类型。

  1. 对于一元运算符,如果操作数的类型是 byte、short 或者 char,那么结果会被提升为 int。
  2. 对于二元运算符,提升规则为:
  • 如果其中有一个操作数的类型为 byte 或者 short,那么这两个操作数都会转换为 int,结果会为 int。
  • 如果其中有一个操作数的类型为 double,那么另一个操作数会被转换为 double,结果会为 double。
  • 如果其中有一个操作数的类型为 float,那么另一个操作数会被转换为 float,结果会为 float。
  • 如果其中有一个操作数的类型为 long,那么另一个操作数会被转换为 long,结果会为 long。

赋值运算符

包含 =、+=、-=、*=、/=、%=、++、—

  1. int number = 5; // 赋值符号右侧赋给左侧,表示将数据量 5 赋值给变量 number
  2. a += b; // 等同于 a = a + b,自带数据类型转换,但如果需要类型转换必须使用强转语法

a++ 表示变量 a 在自身基础上加 1,等同于 a += 1 或 a = a + 1。也可以写作 ++a
区别:++a 前置操作是先完成自增自减,再执行表达式其他部分;a— 后置操作是先完成整个表达式的操作得到结果再进行变量的自增自减。

  1. int a = 5;
  2. int sum = a++ + 10;
  3. System.out.println(sum); // 15
  1. int a = 5;
  2. int sum = ++a + 10;
  3. System.out.println(sum); // 16

比较运算符

包含相等 ==、不等 !=、>、<、>=、<=
在比较之后会得到布尔型的结果,参与比较的表达式不能为布尔类型。

三目

语法 布尔表达式 ? 表达式 1 : 表达式 2; 在布尔表达式得到布尔类型值后,若为真执行表达式1,若为假执行表达式2。

  1. int age = 19;
  2. boolean result = age > 18 ? true : false;
  3. System.out.println(result); // true

逻辑运算符

布尔逻辑运算符包含以下,但只常用前 3 个:

  • 逻辑短路与 &&
  • 逻辑短路或 ||
  • 逻辑非 !
  • 逻辑与 & 读作“位与”
  • 逻辑或 | 读作“位或”
  • 逻辑异或 ^
  1. 与: && 和 &

    • && 是短路运算符,当左边表达式为 false 不会执行右边表达式
    • & 即使左操作数为 false 也会计算右操作数
      1. int i = 10;
      2. int j = 15;
      3. boolean result;
      4. // b = (i > 5 & j > 10); // 把true赋值给b
      5. result = (i > 25 & ((j = 20) > 15)); // 即使 i>25返回false,还要计算右边的
      6. System.out.println("result = " + result); // b = false
      7. System.out.println("j = " + j); // j = 20
  2. 或:|| 和 |

    • || 是短路运算符,当左边表达式为 true 不会计算右边表达式
    • | 本质也是位运算符,只是当它左右两端是 boolean 时表现出和 “||” 相同效果
      1. int i = 10;
      2. int j = 15;
      3. boolean result = i > 5 | ((j = 0) < 5);
      4. System.out.println(result);
      5. System.out.println(j); // 0
  3. 非:! 即 取反

  4. 异或:^ 左右表达式相同为 false,不同为 true
    1. int i = 10;
    2. boolean b;
    3. b = true ^ true; // b为false
    4. b = true ^ false; // b为true
    5. b = false ^ true; // b为true
    6. b = false ^ false; // b为false
    7. b = (i > 5 ^ i < 15); // b为false

    按位运算符

    (开发场景又用不到🙂️…)
    按位运算符是在整数操作数上使用位模式对其执行操作的运算符。包括:
  • 按位与运算符(&)
  • 按位或运算符(|)
  • 按位异或运算符(^)
  • 按位非运算符(~)
  • 左移运算符(<<)
  • 右移运算符(>>)
  • 无符号右移运算符(>>>)

所有按位运算符只处理整数。

  • 1. 按位与运算符(&)

按位与运算符(&)对其两个操作数的相应位进行操作,如果两个位都为1,就返回1,否则就返回0。请注意,按位与(&)对相应操作数的每一位进行运算,而不是对整个操作数进行运算。如下是使用按位与运算符的所有位组合的结果:

  1. 1 & 1 = 1
  2. 1 & 0 = 0
  3. 0 & 1 = 0
  4. 0 & 0 = 0

对于int i = 13 & 3; 13 & 3 的值计算如下。为清晰起见,我们把32位分段为几个8位的。在内存中,所有32为都是连续的,因此,13 & 3 结果为 1,这个值被赋值给 i:

  1. 13 00000000 00000000 00000000 00001101
  2. 3 00000000 00000000 00000000 00000011
  3. ---------------------------------------------
  4. 13 & 3 - 00000000 00000000 00000000 00000001 (等于十进制的1)
  • 2. 按位或运算符(|)

按位或运算符(|)对其操作数的相应位进行操作,只要有一个操作数的位是1,就返回1;否则就返回0。如下是使用按位或运算符的所有位组合的结果:

  1. 1 | 1 = 1
  2. 1 | 0 = 1
  3. 0 | 1 = 1
  4. 0 | 0 = 0

比如,13 | 3 的值可以计算如下,结果为 15:

  1. 13 00000000 00000000 00000000 00001101
  2. 3 00000000 00000000 00000000 00000011
  3. -------------------------------------------
  4. 13 | 3 00000000 00000000 00000000 00001111 (等于十进制的15)
  • 3. 按位异或运算符(^)

按位或运算符(^)对其操作数的相应位进行操作,如果只有一个位是1,就返回1;否则就返回0。如下是使用按位异或运算符(也称XOR)的所有位组合的结果:

  1. 1 ^ 1 = 0
  2. 1 ^ 0 = 1
  3. 0 ^ 1 = 1
  4. 0 ^ 0 = 0

13 ^ 3 的值可以计算如下,结果为 14:

  1. 13 00000000 00000000 00000000 00001101
  2. 3 00000000 00000000 00000000 00000011
  3. ------------------------------------------
  4. 13 ^ 3 00000000 00000000 00000000 00001110 (等于十进制的14)
  • 4. 按位非运算符(~)

按位非运算符(~)对其操作数的每一个位进行操作。它会反转位,也就是说,把1变为0,把0变为1。所以它也称按位取反运算符。如下数使用按位非运算符的所有位组合的结果:

  1. ~1 = 0
  2. ~0 = 1

~13 的值可以计算如下,结果为 -14:

  1. 13 00000000 00000000 00000000 00001101
  2. -----------------------------------------
  3. ~13 11111111 11111111 11111111 11110010 (等于十进制的-14)

(按位左移运算符 和 按位有符号右移运算符 图没了,真好,算了,反正在开发场景也用不到)

数据类型转换

当不同数据类型在进行运算、比较时,会发生数据类型转换。数据类型转换分为:

  • 隐式(自动)转换
  • 强制转换

    自动类型转换

首先思考一个小学数学题,3 + 2.5 = ?
答案应该是 5.5 对不对?那么 5.5 应该是 double 类型的,所以在声明值时,就应该是:

  1. double sum = 3 + 2.5;

所以自动类型转换会自动往大数据类型方向转换。假设当前需要确定 3+’A’ 的值的数据类型。
3 是 int 类型所占 4 个字节,’A’ 是字符 char 类型所占 2 个字节,所以整体就会往 int 类型去转:

  1. int str = 3 + 'A'; // 'A' 按照 ASCII 码转为了数字 65,等于计算了 3+65=68

基本数据类型的大小排序:

  1. byte < short = char < int < long < float < double

进行算数操作时:

  • 不同类型数据进行算数操作,结果就是该类型。例如 5/2得到2,都是 int 类型,而不是 2.5 float 类型
  • 不同类型的数据进行算数操作,结果就是大类型的结果,例如 5/2.0 或5.0/2 都会得到2.5

赋值操作时:

  • 同类型赋值或小数据赋值给大类型变量,都会发生自动类型转换
  • 大类型数据赋值给小类型变量,需要强转

实操当中,确定想要值往某个数据类型去转换的话,使用强制类型转换。

强制类型转换

语法:(目标类型)数据 注意精度的丢失,不会四舍五入,boolean 不参与转换。

  1. // float 转 int
  2. int number = (int)3.14; // 3
  3. // int 转 char
  4. int a = 65;
  5. char str = (char) a; // A
  6. // double 转 int
  7. double d = 1.234;
  8. int a = (int) d; // 1

输入与输出

输出语句

操作完值以后,通常需要输出来查看结果。
使用 java 内置类 System 语法:System.out.println(查看的数据);

  1. // sout 快捷键
  2. System.out.println(3); // 常量
  3. System.out.println(number); // 变量
  4. System.out.println(5 > 3); // 表达式
  5. System.out.println("number 的值是:" + number); // 字符串拼接,加号一侧有字符就为字符串拼接

输入语句

有了输出必然还会有输入,通过使用 Scanner 类完成控制台的输入。Scanner 使用步骤:

  1. 产生一个 scanner 对象(默认情况下 java 只会自动导入 java.lang 包中的类,而输入功能 Scanner 属于 java.util 包,所以需要额外引用)

    1. import java.util.Scanner;
  2. 调用该对象的方法完成输入,根据接受的数据类型决定调用哪种方法

    1. Scanner scan = new Scanner(System.in);
  • 需要接受 int 类型:Int age = scan.nextInt();
  • 需要接受 double 类型:Double height = scan.nextDouble();
  • 需要接受 string 类型:String name = scan.next();
  1. 关闭 scanner ```java // 引入 Scanner 功能 import java.util.Scanner;

// new 出一个 Scanner 类型对象取名叫 scan Scanner scan = new Scanner(System.in);

System.out.println(“请输入”); String name = scan.next(); System.out.println(name);

scan.close(); // 关闭了就不可以再使用了 ```