一、 前言、入门程序、常量
1.1 Java 语言概述。
Java 是一种高级编程语言,而且是面向对象的编程语言。Java 语言是美国 Sun 公司(Stanford University Network),在 1995 年推出的高级的编程语言。Java 语言共同创始人之一:詹姆斯·高斯林 (James Gosling),被称为 Java之父。Java 语言的版本:1.0-1.4,5.0…8.0…13.0,本文笔记用的 jdk 版本为 8.0。
1.2 Java 语言能做什么
Java 语言主要应用在互联网程序的开发领域,网上购物商城、物流、金融、各行各业的门户网站。
1.3 Java 语言的跨平台实现原理
(1) JVM: Java 虚拟机,是专门用来运行 Java 程序的。
(2) 平台:指的就是操作系统,比如 Windows、linux、MacOS 等。
(3) 跨平台: 我们编写的一个 Java 程序,可以做多个操作系统上运行一次编译,到处运行。
(4) 问题思考,如下:
1. Java 程序是跨平台的? ⇒ 正确的 ⇒ 一次编译到处运行。
2. JVM 是跨平台的? ⇒ 错误的 ==> JVM 是实现 Java 程序跨平台的基石。针对不同的操作系统提供不同的 JVM。
而程序在 JVM 中运行。
3. Java 程序的跨平台是依靠 JVM 的不跨平台实现的。正确的
复制代码
1.4 JDK、JRE、JVM 的组成和作用
- JVM: Java 虚拟机,是专门用来运行 Java 程序的,但是不能单独安装。
- JRE: Java 运行环境,包含 JVM(Java 虚拟机,是专门用来运行 Java 程序的)和核心类库。
- JDK: Java 开发工具包,包含 JRE 和开发工具。
- 三者关系: JDK > JRE > JVM
1.1 Java 语言开发环境搭建
JDK 安装,注意事项:
- 注意操作系统是 Windows、linux、MacOS
- 注意操作系统的位数是 32 位还是 64 位
3. 安装 java 相关软件的时候: 安装路径中不允许出现中文和空格(任何开发软件都最好不要安装在中文路径下)
由于安装步骤截图较多,但比较简单,网上一大把,笔者这里就不再赘述,如果有问题,可以私聊笔者!
1.2 常用 DOS 命令的使用
键盘图示如下:
如何进入DOS 命令操作窗口?
- 开始/命令提示符
2. 开始/搜索程序和文件 输入 cmd
4. Windows 键 + R –> 输入 cmd
5. 窗口空白处/按住 shift 键 + 鼠标右键单击 /在此处开命令窗口
6. 常用命令如下表所示:
| 操作 | 说明 |
| :------------------ | :-------------------------------- |
| 盘符名称 | 盘符切换。D: 回车,表示切换到D盘 |
| dir | 查看当前路径下的内容 |
| cd 目录 | 进入单级目录 |
| cd 目录1\目录2.... | 进入多级目录 |
| cd .. | 回退到上一级目录 |
| cd \ | 回退到盘符目录 |
| cls | 清屏 |
| exit | 退出命令提示窗口 |
复制代码
1.3 环境变量 JAVA_HOME 的配置
记事本软件的启动方式?
1.开始/程序/附件/记事本
2.C:/windows/找到notepad.exe命令,双击启动
3.如果在DOS窗口的命令中:
C:\windows> notepad.exe 回车 运行这个命令
首先在C:\windows路径下,寻找是否存在notepad.exe,发现有,直接运行
D:\abc> notepad.exe 回车 运行这个命令
首先:在 D:\abc 路径下,寻找是否存在 notepad.exe,发现没有
其次: 如果发现在当前路径 D:\abc 没有要运行的 notepad.exe 命令,到系统环境变量 path 中寻找
path:... C:\Windows;...,发现path中配置的路径 C:\Windows 有该命令,直接运行.
如果path中配置的所有的路径中都没有要运行的命令,运行报错了.
给Java配置环境变量的意义/目的/作用?
让我们可以在任意路径下运行java开发的相关工具(javac: 编译工具,java: 运行工具)
比如jdk的安装路径:C:\develop\Java\jdk1.8.0_162
配置步骤:
1.创建名称为 JAVA_HOME 的环境变量,取值是 C:\develop\Java\jdk1.8.0_162
2.把步骤1中创建的名称为 JAVA_HOME 的环境变量,添加到系统环境变量 path 中
找到系统环境变量path, 在前面添加: %JAVA_HOME%\bin;...
3.如果在DOS窗口的命令中:
C:\develop\Java\jdk1.8.0_162\bin> javac.exe 回车 运行这个命令
首先在C:\develop\Java\jdk1.8.0_162\bin路径下,寻找是否存在javac.exe,发现有,
直接运行
D:\abc> javac.exe 回车 运行这个命令 首先:在D:\abc路径下,寻找是否存在javac.exe,发现没有
其次: 如果发现在当前路径 D:\abc 没有要运行的 javac.exe 命令,到系统环境变量path中寻找
path:... %JAVA_HOME%\bin;..., 发现 path 中配置的名称为 JAVA_HOME 的环境变量,对应的路径
C:\develop\Java\jdk1.8.0_162\bin 中有要运行的 javac.exe 命令,直接运行,
如果 path 中配置的所有路径中,都没有要运行的 javac.exe 命令,运行报错了
寻找名称为JAVA_HOME的环境变量,找到后,使用其配置的具体路径进行替换:
path:... C:\develop\Java\jdk1.8.0_162\bin;...,
替换后的路径: C:\develop\Java\jdk1.8.0_162\bin 中有 javac 命令,就可以直接运行
复制代码
二、HelloWorld 入门程序
2.1 程序开发的步骤
1. 源程序:
- 程序员写的程序;
- 程序员在自己可以看得懂得程序;
- 程序:字母、数字、其他符号;
源程序是程序员编写的,程序员自己可以看得懂得程序,本质就是一个文本文件,但是扩展名不是 .txt,而是 .java。
2. 生产JVM可以执行的字节码(.class)文件
- JVM:叫做 Java 虚拟机,是专门用来运行 Java 程序的。但是 JVM 是一个二货,只能识别 0 和 1,而存储 0 和 1 的文件叫做 字节码文件(.class文件)
- 如何把源文件(程序)翻译成JVM能够执行的字节码文件(程序)呢? 使用 javac 命令(编译命令), 使用格式:javac 文件名.java 例如:编译HelloWorld.java 源文件: javac HelloWorld.java,生成一个字节码文件:HelloWorld.class
3. 把字节码文件交给JVM执行
不管是源文件(程序)还是字节码文件(程序)都存储在硬盘中? 不会自动执行,如何把字节码文件交给 JVM 执行呢? 使用 java 命令(运行命令)。 使用格式: java 文件名 例子:java HelloWorld
2.2 HelloWorld 案例的编写编译运行
1. 编写源文件。 创建一个名称为 HelloWorld.txt 的文本文件,把扩展名修改为 .java,打开 HelloWorld.java 源文件,输入以下内容,并保存(ctrl+s)。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
复制代码
2. 编译: javac命令。 根据 .java源文件 生产对应的 .class文件(字节码文件)。 使用 javac 命令的格式:javac 文件名.java。javac HelloWorld.java。注意:
- 保证当前路径下 javac命令 可以使用。
- 保证当前路径下有要进行编译的 源(.java)文件。
- 使用编译javac命令时,文件名后面必须写 扩展名.java。
3.运行: java命令。 把 字节码(.class)文件 交给 jvm 执行。使用 java 命令的格式:java 文件名,java HelloWorld,同样要注意:
- 保证当前路径下 java 命令 可以使用。
- 保证当前路径下有要进行运行的 字节码(.class)文件。
- 使用运行 java 命令 时,文件名后面不能写 扩展名.class。
2.3 初学者编写 HelloWorld 常见问题
- 非法字符问题。Java 中的符号都是英文格式的。
- 大小写问题。Java 语言对 大小写敏感(区分大小写)。
- 在系统中显示文件的扩展名,避免出现 HelloWorld.java.txt 文件。
- 编译命令后的 java文件名需要带文件后缀 .java。
- 运行命令后的 class文件名(类名) 不带文件 后缀.class。
- 不要把 main 写成 mian。
2.4 Notepad++ 软件的安装和配置
软件下载地址:
链接:https://pan.baidu.com/s/15DaxTdbiVqGVjrRlU2lXbQ
提取码:6y7p
--来自百度网盘超级会员V6的分享
复制代码
三、注释和关键字
3.1 注释
概念: 在代码中添加注释可提高代码的可读性。注释中包含了程序的信息,可以帮助程序员更好地阅读和理解程序。在 Java 源程序文件 的任意位置都可以添加注释,且 Java 编译器不编译代码中的注释,也就是说代码中的注释对程序不产生任何影响。所以开发者不仅可以在注释中编写代码的说明文字、设计者的个人信息,还可以使用注释来屏蔽某些不希望执行的代码。
分类: Java 提供了 3 种代码注释,分别为单行注释、多行注释和文档注释。
1、单行注释://
为单行注释标记,从符号 //
开始直到换行为止的所有内容均作为注释而被编译器忽略。语法格式如下:
// 注释内容
int age ; // 声明int型变量,用于保存年龄信息
复制代码
2、多行注释: /* */
为多行注释标记,符号 /*
与 */
之间的所有内容均为注释内容。注释中的内容可以换行。语法格式如下:
/*
注释内容1
注释内容2
…
*/
复制代码
3、文档注释: /**…*/
为文档注释标记。符号 /**
与 */
之间的内容均为文档注释内容。当文档注释出现在声明(如类的声明、类的成员变量声明、类的成员方法声明等)之前时,会被 Javadoc 文档工具 读取作为 Javadoc 文档内容。文档注释的格式与多行注释的格式相同。对于初学者而言,文档注释并不是很重要,了解即可。示例如下:
说明:一定要养成良好的编码习惯。软件编码规范中提到 可读性第一,效率第二,所以程序员必须要在程序中添加适量的注释来提高程序的可读性和可维护性。建议程序中的注释总量要占程序代码总量的 20%~50%。
3.2 关键字
引入:邮箱: @前面是用户名,@后面是使用的是哪家的邮箱。
zhangsan@163.com 正确的
zhangsan@qq.com 正确的
zhangsan_nigulasi@qq.com 正确的
zhangsan@nigulasi@qq.com 错误的
@理解为在邮箱当中具有特殊的含义和使用方式,不能胡乱用,看做邮箱名称中的关键字
复制代码
换而言之,关键字是 Java 中已经被赋予特定意义的一些单词,不可以把这些字作为标识符来使用。关键字中的所有字母都是小写的,或者在高级编辑器中彩色显示。
Java中的关键字如下表所示:
int | public | this | finally | boolean | abstract |
---|---|---|---|---|---|
continue | float | long | short | throw | throws |
return | break | for | static | new | interface |
if | goto | default | byte | do | case |
strictfp | package | super | void | try | switch |
else | catch | implements | private | final | class |
extends | volatile | while | synchronized | instanceof | char |
proteced | import | transient | dafault | double |
3.3 标识符
标识符可以简单地理解为一个名字,用来标识类名、变量名、方法名、数组名等的有效字符序列。Java 规定标识符由 任意顺序的字母、下划线(_)、美元符号($)和数字组成,并且第一个字符不能是数字。标识符不能是 Java 中的保留关键字。 示例:
// 合法标识符如下:
time
akb48
_interface
O_o
BMW
$$$
// 下面这些都不是合法的标识符:
300warrior // 不可以用数字开头
public // 不可以使用关键字
User Name // 不可以用空格断开
复制代码
常见错误:用中文命名标识符是非常不好的编码习惯。当编译环境的字符编码集发生改变后,代码中所有的中文标识符全部会显示成乱码,程序将无法维护。因为 Java 是一种可以跨平台的开发语言,所以发生中文标识符显示成乱码这种情况的概率非常大。编写 Java 代码有一套公认的命名规范:
- 类名:通常使用名词,第一个单词字母必须大写,后续单词首字母大写。(大驼峰式)
- 方法名:通常使用动词,第一个单词首字母小写,后续单词首字母大写。(小驼峰式)
- 变量:第一个单词首字母小写,后续单词首字母大写。(小驼峰式)
- 常量:所有字母均大写。
- 单词的拼接:通常使用 userLastName 方式拼接单词,而不是 user_last_name。
四、常量与变量
4.1 常量的概念和分类
引入:
数学中有常数的概念:
y = x + 5; //数字5是一个常数,其值不可以发生改变
b = a + 5.5; //数字5.5是一个常数,其值不可以发生改变
数学中对常数进行了分类:
数字5是一个整数常数, 其值不可以发生改变
数字5.5是一个小数数常数, 其值不可以发生改变
复制代码
数学中的常数,对应到 java 中叫常量,数学中的常数有分类,java 中的常量也有分类,而且比数学中的分类更加丰富。
1、概念: 在程序的执行过程中,其值不可以发生改变的量。
2、分类:
-
整数常量:1314、520
-
小数常量:13.14、5.20
-
字符常量:java 中规定字符常量必须使用单引号
''
引起来,而且单引号''
中只能写一个字符(不能不写,也不能写2个以上) 举例:A:'a' 正确的 B: '' 里面什么都没有写,错误的 C:' ' 里面有一个空格,正确的 D:'ab' 错误的 E: '好' 正确的 F: '女子' 错误的 复制代码
-
布尔常量:只有两个值 true 和 false。true:表示肯定的,对的,是的,正确的,成立的。false:表示否定的,错的,不是的,却无的,不成立的。
-
字符串常量:java 中规定字符串常量必须使用双引号
""
引起来,而且双引号""
中可以写多个字符(0个、1个、2个….), 举例:A:"a" 正确的 B: "" 里面什么都没有写 正确的 C:" " 里面有一个空格 正确的 D:"ab" 正确的 E:"好" 正确的 F:"女子"正确的 复制代码
-
空常量:null
4.2 打印不同类型的常量
同 C语言 一样,Java 程序想要在控制台输出文字,需要调用一个已有的方法,方法如下:
System.out.print("Hello!"); // 此方法输出"Hello"后不会自动换行,光标停留同一行的末尾
复制代码
但与 C语言 不同的是,Java 又提供了一个输出文字后自动换行的方法,这个方法在原有的 print 后面加上了 ln 后缀,方法如下:
System.out.println("Hello!"); // 此方法输出"Hello"后会自动换行,光标停留下一行的开头
复制代码
打印不同类型的常量,示例如下:
public class SystemOutDemo {
public static void main(String[] args) {
//你之前怎么写常量的,就直接在println()小括号中怎么写,就可以在控制台输出指定的常量。
//(1)整数常量:1314 520
System.out.println(1314);
System.out.println(520);
//(2)小数常量: 13.14 5.20
System.out.println(13.14);
System.out.println(5.20);
//(3)字符常量:
System.out.println('a');
//System.out.println('');//错误的: ''不能没有字符
System.out.println(' ');//正确的: ' '有一个空格
System.out.println('好');//正确的: ' '有一个空格
//System.out.println('女子');//错误的: '女子'不能写2个及以上的字符
//(4)字符串常量
System.out.println("a");
System.out.println("");
System.out.println(" ");
System.out.println("ab");
System.out.println("好想你");
System.out.println("女子");
//(5)布尔常量
System.out.println(true);
System.out.println(false);
//(6)空常量
//System.out.println(null);//错误: 不能直接打印空常量null
}
}
复制代码
4.3 变量和数据类型【重要】
引入:
数学中有个常数的概念:
y = x + 10; //整数数字10是不可以发生变化的
b = a + 6.6; //小数数字6.6是不可以发生变化的
数学中的数字(常量)是有分类的,对应java中的常量也是有分类的,之前已经说过
x,y 是可以发生变化的
x: 2 y: 12、x: 6 y: 16,x,y 中的数据是可以发生变化的,而且x,y内部的数据也是有类型(整数)
a,b 是可以发生变化的
a: 2.2 b: 8.8、a: 3.3 b: 9.9 a,b 中的数据是可以发生变化的,而且 a,b 内部的数据也是有类型(小数)
像x,y,a,b 这样东西,里面的数据是可以发生变化的,而且数据是有类型的,我们把这样的东西称为变量(容器: 里面只能放一个数据)
变量为什么要有这么多的分类: 不同的分类,占用的字节数不同,取值范围就不同,使用的场景也就不同
复制代码
1、变量概念: 在程序的执行过程中,其值可以在一定范围内发生改变的量。可以把变量理解成为一个 容器,例如一个空烧杯,给变量赋值就相当于给烧杯倒水。如下图所示的那样,变量可以不断更换值,就像烧杯可以反复使用一样:
2、分类:
1.整数:
byte 1个字节 -128到127
short 2个字节 正负3万多
int 4个字节 正负21亿 整数默认int类型
long 8个字节 大概19位数字 表示long类型数据后面需要加 L/l
2.小数:
float 4个字节 表示float数据后面需要加 F/f
注意: 虽然float占4个字节,但是由于采用科学计数法,取值范围远远超过long
double 8个字节 小数默认double类型
3.字符:
char 2个字节
4.布尔:
boolean 1个字节 取值为true或者false
复制代码
3、变量定义格式图解分析:
变量的理解:
1.变量的本质就是内存中的一块空间,空间的大小由数据类型决定。
2.要想找到变量对应的内存空间的数据,需要给变量对应的内存空间起个名字,叫做变量名称。对于变量的命名并不是任意的,
应遵循以下几条规则:
a.变量名必须是一个有效的标识符。
b.变量名不可以使用 Java 中的关键字。
c.在同一个大括号范围内,变量名不能重复。
d.应选择有意义的单词作为变量名。
说明:在 Java 中允许使用汉字或其他语言文字作为变量名,如 **int 年龄 = 21;** 在程序运行时不会出现错误,但建议尽量不要使用
这些语言文字作为变量名。
3.变量对应的内存空间中必须有数据才能使用,这种向变量内存空间中,存储数据的过程叫做初始化或者赋值
变量的定义格式一(先挖坑,然后种萝卜):
数据类型 变量名称;//先挖坑
变量名称 = 数据值;//再种萝卜
变量的定义格式二(挖坑,同时种萝卜):
数据类型 变量名称 = 数据值;//挖坑,同时种萝卜
变量的定义格式三(先挖多个坑,然后分别向每个坑中种萝卜):
数据类型 变量名称1,变量名称2,变量名称3;//先挖多个坑
变量名称1 = 数据值1;//向第一个坑中种萝卜
变量名称2 = 数据值2;//向第二个坑中种萝卜
变量名称3 = 数据值3;//向第三个坑中种萝卜
变量的定义格式四(挖多个坑,同时分别向每个坑中种萝卜):
数据类型 变量名称1 = 数据值1,变量名称2 = 数据值2,变量名称3 =数据值3;
复制代码
图解:
为什么要声明变量呢?简单地说,就是要告诉编译器这个变量属于哪一种数据类型,这样编译器才知道需要分配多少空间给它,以及它可以存放什么样的数据。
4、定义8种变量1:
public class VariableDemo {
public static void main(String[] args) {
/*
变量的定义格式一(先挖坑,然后种萝卜):
数据类型 变量名称;//先挖坑
变量名称 = 数据值;//再种萝卜
*/
byte a;//挖了一个byte类型(1个字节)的坑,给这个坑起个名字叫a
a = 66;//把数字66存储到byte类型的坑a中
System.out.println(a);//打印byte类型(1个字节)的坑a中的内容: 66
a = 88;//把数字88存储到byte类型的坑a中,原有的数据66将被替换
System.out.println(a);//打印byte类型(1个字节)的坑a中的内容: 88
/*
变量的定义格式二(挖坑,同时种萝卜):
数据类型 变量名称 = 数据值;//挖坑,同时种萝卜
*/
short b = 100;//挖了一个short类型(2个字节)的坑,给这个坑起个名字叫b,同时向这个坑中存储数字100
System.out.println(b);//打印short类型(2个字节)的坑b中的内容: 100
/*
变量的定义格式三(先挖多个坑,然后分别向每个坑中种萝卜):
数据类型 变量名称1,变量名称2,变量名称3;//先挖多个坑
变量名称1 = 数据值1;//向第一个坑中种萝卜
变量名称2 = 数据值2;//向第二个坑中种萝卜
变量名称3 = 数据值3;//向第三个坑中种萝卜
*/
int c, d, e;//挖了三个int类型(4个字节)的坑,给每个坑分别起名为c,d,e
c = 200;//把数字200存储到int类型的坑c中
d = 300;//把数字300存储到int类型的坑d中
e = 500;//把数字500存储到int类型的坑e中
System.out.println(c);//打印int类型(4个字节)的坑c中的内容: 200
System.out.println(d);//打印int类型(4个字节)的坑d中的内容: 300
System.out.println(e);//打印int类型(4个字节)的坑e中的内容: 500
/*
变量的定义格式四(挖多个坑,同时分别向每个坑中种萝卜):
数据类型 变量名称1 = 数据值1,变量名称2 = 数据值2,变量名称3 =数据值3 ;
*/
//挖了三个long类型的坑,名字分别叫做f,g,h
//同时把600L存储到坑f中
//同时把700L存储到坑g中
//同时把800L存储到坑h中
long f = 600L, g = 700L, h = 800L;
System.out.println(f);//打印long类型(8个字节)的坑f中的内容: 600
System.out.println(g);//打印long类型(8个字节)的坑g中的内容: 700
System.out.println(h);//打印long类型(8个字节)的坑h中的内容: 800
}
}
复制代码
5、定义8种变量2:
public class VariableDemo {
public static void main(String[] args) {
//float类型
//定义float类型变量a,并初始化
//大萝卜不能直接存储到小坑中
//float a = 6.6;//错误: 6.6默认是double类型,占8个字节,不能存储到4个字节的float变量中
float a = 6.6F;
System.out.println(a);//打印变量a中的内容
//double类型
//定义double类型变量b,并初始化
double b = 8.8;
System.out.println(b);//打印变量b中的内容
//char类型
//定义char类型变量c1,并初始化
char c1 = 'a';
System.out.println(c1);//打印变量c1中的内容
//char c2 = '';//错误: ''中不能不写字符
//System.out.println(c2);//打印变量c2中的内容
//char c3 = 'ab';//错误: ''中不能写2个及以上的字符
//System.out.println(c3);//打印变量c3中的内容
//boolean类型: 只能存储true或者false
//定义boolean类型变量d1,并初始化
boolean d1 = true;
System.out.println(d1);//打印变量d1中的内容
d1 = false;//把false存储到变量d1中,原有的数据将被替换
System.out.println(d1);//打印变量d1中的内容
//d1 = 100;//错误: 数据类型不匹配
//System.out.println(d1);//打印变量d1中的内容
}
}
复制代码
变量的注意事项:定义的变量,不赋值不能使用。定义 long 类型的变量时,需要在整数的后面加 L(大小写均可,建议大写)。同理,定义 float 类型的变量时,需要在小数的后面加 F(大小写均可,建议大写)。
4.4 数据类型转换
类型转换是将一个值从一种数据类型更改为另一种数据类型的过程。例如,可以将 String 类型数据 457
转换为一个数值型,而且可以将任意类型的数据转换为 String 类型。数据类型转换有两种方式,即 隐式转换与显式转换。 如果从低精度数据类型向高精度数据类型转换,则永远不会溢出,并且总是成功的;而把高精度数据类型向低精度数据类型转换则必然会有信息丢失,甚至有可能失败。这种转换规则就像下图所示的两个场景,高精度相当于一个大水杯,低精度相当于一个小水杯,大水杯可以轻松装下小水杯中所有的水,但小水杯无法装下大水杯中所有的水,装不下的部分必然会溢出。
从低级类型向高级类型的转换,系统将自动执行,程序员无须进行任何操作。这种类型的转换称为 隐式转换,也可以称为自动转换。 下列基本数据类型会涉及数据转换(不包括逻辑类型),这些类型按精度从 “低”到“高” 排列的顺序为 byte < short < int < long < float < double,可对照下图,其中 char 类型比较特殊,它可以与部分 int 型数字兼容,且不会发生精度变化。
隐式转换具体分析如下:
Java 程序中要求参与的计算的数据,必须要保证数据类型的一致性,如果数据类型不一致将发生类型的转换。
int + int
int + long ==> long + long (把int转换成long: 从小到大,自动类型转换,不需要代码的干预)
int + long ==> int + int (把long转成int: 从大到小,强制类型转换,必须手动代码完成)
总结:
1.隐式转换(自动类型转换)概念:
取值范围小的数据或者变量可以直接赋值给取值范围大的变量(小萝卜可以直接放入大坑中)
2.特点:
(1)自动类型转换是自动完成的,不需要代码的干预
(2)byte/short/char类型数据,只要参加运算会自动转换为int类型
(3)byte、short、char-->int-->long-->float-->double
举例:有一个byte类型(1个字节)的数字5: 00000101
byte类型自动类型转换成short类型(2个字节):在左侧补充1个字节的0,因为左侧补充的都是0,对原有数据是没有影响的,仍然是5,
00000000 00000101
byte类型自动类型转换成int类型(4个字节):
在左侧补充3个字节的0,因为左侧补充的都是0,对原有数据是没有影响的,仍然是5
00000000 00000000 00000000 00000101
byte类型自动类型转换成long类型(8个字节):
在左侧补充7个字节的0,因为左侧补充的都是0,对原有数据是没有影响的,仍然是5
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101
总结:根据需求,在数据前面补充若干字节的0,因为补充的都是0,对原有数据大小是没有影响的(打肿脸充胖子)
复制代码
示例代码1,如下:
public class ConvertDemo {
public static void main(String[] args) {
int i = 1;
byte b = 2;
/*
b是byte类型,i是int类型,运算时类型不一致,会发生自动类型转换
byte类型(1个字节)的b会自动转换成int类型(4个字节):在byte类型的b左侧补充3个字节的0
最终变成了两个int数据相加,结果是int类型(占用4个字节),不能直接赋值给左侧的byte类型的变量x,占用1个字节
大萝卜不能直接放入小坑中
*/
//byte x = b + i;
//System.out.println(x);
/*
b是byte类型,i是int类型,运算时类型不一致,会发生自动类型转换
byte类型(1个字节)的b会自动转换成int类型(4个字节):在byte类型的b左侧补充3个字节的0
最终变成了两个int数据相加,结果是int类型(占用4个字节),可以直接赋值给左侧的int类型的变量y,占用4个字节
大萝卜可以直接放入大坑中
*/
int y = b + i;
System.out.println(y);//3
}
}
复制代码
示例代码2,如下:
public class ConvertDemo {
public static void main(String[] args) {
int i = 1;
double d = 2.5;
/*
i是int类型,d是double类型,运算时类型不一致,会发生自动类型转换
int类型(4个字节)的i会自动转换成double类型(8个字节): 最终效果就是在整数后面添加.0 比如: 1变成1.0
最终变成了两个double数据相加,结果是double类型(占用8个字节),不能直接赋值给左侧的int类型的变量x,占用4个字节
大萝卜不能直接放入小坑中
*/
//int x = i + d;
//System.out.println(x);
/*
i是int类型,d是double类型,运算时类型不一致,会发生自动类型转换
int类型(4个字节)的i会自动转换成double类型(8个字节): 最终效果就是在整数后面添加.0 比如: 1变成1.0
最终变成了两个double数据相加,结果是double类型(占用8个字节),可以直接赋值给左侧的double类型的变量y,占用8个字节
大萝卜可以直接放入大坑中
*/
double y = i + d;
System.out.println(y);
}
}
复制代码
显式转换具体分析如下:
当把高精度的变量的值赋给低精度的变量时,必须使用显式类型转换(又称强制类型转换),
当执行显式类型转换时可能会导致精度缺失。语法如下:
(类型名) 要转换的值
取值范围大的数据或者变量不能直接赋值给取值范围小的变量(大萝卜不能直接放入小坑中),解决方案:
(1) 把坑变大
(2) 把萝卜变小(强制类型转换)
2.格式:
转后类型 变量名称 = (转后类型) 转前数据或者变量;
long类型(8个字节)的数字5:
long num = 5L;
long类型强制类型转换成int类型(4个字节):
int a = (int)num;//把num中的数据强制类型转换成int类型,并把结果赋值给int变量a
举例: 有一个long类型(8个字节)的数字5:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101
long类型强制类型转换成int类型(4个字节):
砍掉左侧的四个字节的内容,因为砍掉的都是数字0,所以对最终的结果数据没有影响仍然是5
00000000 00000000 00000000 00000101
long类型强制类型转换成short类型(2个字节):
砍掉左侧的六个字节的内容,因为砍掉的都是数字0,所以对最终的结果数据没有影响仍然是5
00000000 00000101
long类型强制类型转换成byte类型(1个字节):
砍掉左侧的七个字节的内容,因为砍掉的都是数字0,所以对最终的结果数据没有影响仍然是5
00000101
总结: 根据需求,砍掉数据左侧的若干字节的数据,只要砍掉的都是0,对原数据没有影响
但是只要砍掉的数据中包含1,就会对原数据产生影响(可能会损失精度)
复制代码
示例代码3,如下:
public class ConvertDemo {
public static void main(String[] args) {
double d = 1.5;
/*
左侧d是double类型(占8个字节),右侧的int类型的变量x(占4个字节)
相当于: 左侧是较大的数据,右侧的变量比较小
大萝卜不能直接放入小坑中
*/
//int x = d;
//System.out.println(x);
/*
左侧d是double类型(占8个字节),右侧的int类型的变量x(占4个字节)
double数据是不能直接赋值给int变量的: 大萝卜不能直接放入小坑中
但是进行了强制类型转换,把double数据强制转换成int数据
double强制类型转换成int: 直接把小数部分干掉,会损失精度
*/
int y = (int) d;
System.out.println(y);
}
}
复制代码
示例代码4,如下:
public class ConvertDemo {
public static void main(String[] args) {
short s = 1;
/*
s是short类型,1是int类型,运算时类型不一致,会发生自动类型转换
short类型(2个字节)的s会自动转换成int类型(4个字节):在short类型的s左侧补充2个字节的0
最终变成了两个int数据相加,结果是int类型(占用4个字节),不能直接赋值给左侧的short类型的变量s,占用2个字节
大萝卜不能直接放入小坑中
*/
//s = s + 1;
//System.out.println(s);
/*
s是short类型,1是int类型,运算时类型不一致,会发生自动类型转换
short类型(2个字节)的s会自动转换成int类型(4个字节):在short类型的s左侧补充2个字节的0
最终变成了两个int数据相加,结果是int类型(占用4个字节),不能直接赋值给左侧的short类型的变量s,占用2个字节
但是在赋值之前把int类型的结果,强制转换成short类型(砍掉左侧的2个字节的内容),
由于砍掉的2个字节都是0,所以最终的结果没有影响,仍然是2
把萝卜变小
*/
s = (short) (s + 1);
System.out.println(s);
}
}
复制代码
图解(其它案例):
4.5 ASCII 码表
计算机是一个二货,只能存储 0和1,所以存储到计算机中的所有内容都会转换成 0和1 进行存储。所以我们在计算机中存储的字符也不例外,也需要把字符转换成 0和1 进行存储,问题: 如何把字符转换成 0和1 呢? 通过 ASCII 编码表: 存储字符和数字对应关系的一张表格。 存储字符时:需要查找 ASCII 码表,找到字符对应的数字,将数字转换为二进制数存放到计算机中。
'A' ---> 65 ---> 1000001 大写字母是连续的,ASCII编码值依次+1
'a' ---> 97 ---> 1100001 小写字母是连续的,ASCII编码值依次+1
'0' ---> 48 ---> 110000 数字字符是连续的,ASCII编码值依次+1
使用字符时:将对应的二进制数转换为十进制 找到ASC表中对应的字符
1000001 ---> 65 ---> 'A'
1100001 ---> 97 ---> 'a'
110000 ---> 48 ---> '0'
复制代码
ASCII 码表如下图所示:
int 类型和 char 类型的运算原理,如下:
public class ConvertDemo {
public static void main(String[] args) {
//定义char类型的变量ch,并初始化为'A'
char ch = 'A';
System.out.println(ch);//A
/*
自动类型转换中:
byte/short/char类型,只要参加运算,会自动转换为int类型
ch是char类型,在参加运算时,自动转为int类型
问题:
char类型如何转换为int类型的数字呢?
查看ASCII编码表: 找到'A'对应的数字是65,然后参与运算
*/
System.out.println(ch + 1);//66
/*
自动类型转换中:
byte/short/char类型,只要参加运算,会自动转换为int类型
ch是char类型,在参加运算时,自动转为int类型
查看ASCII编码表: 找到'A'对应的数字是65,然后参与运算
所以: ch + 1 的结果是66
然后把int数字66强制转换成char类型的数据
问题:
int类型的数据如何强制转换成char类型数据呢?
查看ASCII编码表: 找到int数字66对应的字符'B'显示出来
*/
System.out.println((char) (ch + 1));//B
}
}
复制代码
五、计算机中的进制与字节
5.1 进制及转换
5.2 计算机中的存储单位(2的10次方就是1024)
1.位(bit): 计算机中存储一个数字0或者1所占用的空间 简写成b
2.字节(Byte): 8个位占用的空间叫做一个字节,简写成B。字节是我们常见的计算机中最小存储单元。
1B = 8b
1024B = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
....
复制代码
务必记住:1个字节是8位
六、运算符
运算符:对常量或者变量进行操作的符号。表达式:用运算符把常量或者变量连接起来符合 java 语法的式子就可以称为表达式。
6.1 算术运算符
Java 中的算术运算符主要有 +(加号)、-(减号)、*(乘号)、/(除号)、%(求余),它们都是二元运算符。Java 中算术运算符的功能及使用方式如下表所示:
运 算 符 | 说 明 | 实 例 | 结 果 |
---|---|---|---|
+ | 加 | 12.45f + 15 | 27.45 |
– | 减 | 4.56 – 0.16 | 4.4 |
* | 乘 | 5L * 12.45f | 62.25 |
/ | 除 | 7 / 2 | 3 |
% | 取余 | 12 % 10 | 2 |
其中,“+”和“-” 运算符还可以作为数据的正负符号,如 +5、-7。说明:“+”运算符也有拼接字符串的功能。下面分别演示算术运算符的用法。 |
【示例1】算术运算符加减乘除。示例代码如下:
public class OperatorDemo {
public static void main(String[] args) {
int a = 3;
int b = 2;
System.out.println(a + b);//3 + 2: 5
System.out.println(a - b);//3 - 2: 1
System.out.println(a * b);//3 * 2: 6
//3/2: int/int 结果必然是int类型
System.out.println(a / b);//3 / 2: 1
//int * double / int ==> double / int ==> double / double ==> double
System.out.println((a * 1.0) / b);//3.0 / 2 ==> 3.0/2.0 ==> 1.5
}
}
复制代码
【示例2】算术运算符%。示例代码如下:
/*
%运算符: 取余数(模)运算符
被除数 ÷ 除数 = 商(/: 取的就是商) ...... 余数(%: 取的就是余数)
作用:
1.判断数字的奇偶性:
数字%2 结果是0 说明数字是偶数
数字%2 结果不是0 说明数字是奇数
2.判断一个数字是否能够被另外一个数字整除
结果为0: 说明可以整除
结果不为0: 说明不可以整除
3.可以把%和/结合使用计算数字的个位,十位,百位,千位
比如有个int变量num,保存数字1234
int num = 1234;
个位: num%10
十位: num/10%10
百位: num/100%10
千位: num/1000%10
*/
public class OperatorDemo {
public static void main(String[] args) {
System.out.println(10 % 2);//0 说明10是偶数
System.out.println(11 % 2);//1 说明11是奇数
System.out.println(100 % 25);//0 说明100可以被25整除
System.out.println(100 % 26);//22 说明100不可以被26整除
System.out.println("---------------");
int num = 1234;
System.out.println(num % 10);//4: 个位 1234 ÷ 10 = 商123 .... 余数4(%)
//System.out.println(num/10);//123 1234 ÷ 10 = 商123(/) .... 余数4(%)
System.out.println(num / 10 % 10);//3 十位 123 ÷ 10 = 商12(/) ... 余数3(%)
//System.out.println(num/100);//12 1234 ÷ 100 = 商12(/) ... 余数34(%)
System.out.println(num / 100 % 10);//2 百位 12 ÷ 10 = 商1(/) ... 余数2(%)
System.out.println(num / 1000 % 10);//1 千位
}
}
复制代码
【示例3】算术运算符+的特殊用法。示例代码如下:
/*
+符号的作用
1.数学中的加法运算(数字相加,字符相加)
2.字符串的拼接(把两个字符串连在一起)
*/
public class OperatorDemo {
public static void main(String[] args) {
System.out.println(5 + 5);//10
/*
int + char ==> int + int ==> int
需要:
char ==> int 查看ASCII码表 'A'对应65
*/
System.out.println(5 + 'A');//5 + 65: 70
/*
自动类型转换中:
byte/short/char类型,只要参加运算,会自动转换为int类型
char + char ==> int + int ==> int
需要:
char ==> int 查看ASCII码表 'A'对应65
char ==> int 查看ASCII码表 'B'对应66
*/
System.out.println('A' + 'B');//65 + 66: 131
System.out.println("Hello" + "World");
//"5+5="+5+5: 从左向右计算
//先计算"5+5="+5: 此处+号代表字符串的连接 结果是"5+5=5"
//然后"5+5=5"+5: 此处+号代表字符串的连接 结果是"5+5=55"
System.out.println("5+5=" + 5 + 5);//5+5=55
//()的优先级是比较高的,所以先计算5+5 结果10
//然后"5+5="+10: 此处+号代表字符串的连接 结果是"5+5=10"
System.out.println("5+5=" + (5 + 5));//5+5=10
}
}
复制代码
6.2 赋值运算符
赋值运算符用符号 “=” 表示,它是一个二元运算符(对两个操作数作处理),其功能是将右方操作数所含的值赋给左方的操作数。例如:
int a = 100; // 该表达式是将100赋值给变量a
/*左方的操作数必须是一个量,而右边的操作数则可以是变量(如a、number)、
常量(如123、"book")、有效的表达式(如45*12)。*/
复制代码
和其他主流编程语言一样,Java 中也有复合赋值运算符。所谓的复合赋值运算符,就是将赋值运算符与其他运算符合并成一个运算符来使用,从而同时实现两种运算符的效果。Java 中的复合运算符如下表所示:
运 算 符 | 说 明 | 举 例 | 等 价 效 果 |
---|---|---|---|
+= | 相加结果赋予左侧 | a += b; | a = a + b; |
-= | 相减结果赋予左侧 | a -= b; | a = a – b; |
*= | 相乘结果赋予左侧 | a *= b; | a = a * b; |
/= | 相除结果赋予左侧 | a /= b; | a = a / b; |
%= | 取余结果赋予左侧 | a %= b; | a = a % b; |
&= | 与结果赋予左侧 | a &= b; | a = a & b; |
|= | 或结果赋予左侧 | a |= b; | a = a | b; |
^= | 异或结果赋予左侧 | a ^= b; | a = a ^ b; |
<<= | 左移结果赋予左侧 | a <<= b; | a = a << b; |
>>= | 右移结果赋予左侧 | a >>= b; | a = a >> b; |
>>>= | 无符号右移结果赋予左侧 | a >>>= b; | a = a >>> b; |
以“+=”为例,虽然“a += 1”与“a = a + 1”二者最后的计算结果是相同的,但是在不同场景下,两种运算符都有各自的优势和劣势。 |
【示例4】赋值运算符的使用场景。示例代码如下:
public class OperatorDemo {
public static void main(String[] args) {
int a = 10, b = 20;
a += b;//a = a + b
System.out.println(a);//30
System.out.println(b);//20
int c = 30, d = 20;
c %= d;//c = c % d = 30%20 = 10
System.out.println(c);//10
System.out.println(d);//20
}
}
复制代码
【示例5】复合赋值运算符的特点。示例代码如下:
public class OperatorDemo {
/*
赋值运算符特点
1.+=,-=,/=,*=,%= 运算结果的数据类型和左侧变量的数据类型不一致,隐藏强制类型转换
2.整数常量只要不超出所赋值的整数变量的取值范围,可以直接赋值,内部隐藏强制类型转换
*/
public static void main(String[] args) {
short s = 1;
/*
s是short类型,1是int类型,运算时类型不一致,会发生自动类型转换
short类型(2个字节)的s会自动转换成int类型(4个字节):在short类型的s左侧补充2个字节的0
最终变成了两个int数据相加,结果是int类型(占用4个字节),不能直接赋值给左侧的short类型的变量s,占用2个字节
大萝卜不能直接放入小坑中
*/
//s = s + 1;
//System.out.println(s);
/*
s是short类型,1是int类型,运算时类型不一致,会发生自动类型转换
short类型(2个字节)的s会自动转换成int类型(4个字节):在short类型的s左侧补充2个字节的0
最终变成了两个int数据相加,结果是int类型(占用4个字节),不能直接赋值给左侧的short类型的变量s,占用2个字节
但是在赋值之前把int类型的结果,强制转换成short类型(砍掉左侧的2个字节的内容),
由于砍掉的2个字节都是0,所以最终的结果没有影响,仍然是2
把萝卜变小
*/
s = (short) (s + 1);
System.out.println(s); //2
short s2 = 1;
/*
+=,-=,/=,*=,%= 运算结果的数据类型和左侧变量的数据类型不一致,隐藏强制类型转换
*/
s2 += 1;//s2 = (short)(s2 + 1);
System.out.println(s2); //2
/*
右侧10是int类型(4个字节),左侧变量byte类型(1个字节)
按照道理来讲: 大萝卜是不可以直接放入小坑中的
现在为什么可以呢?
原因是数字10是一个常量,值并没有超出byte的取值范围
所以可以直接赋值,内部会帮助我们进行强制类型转换
等价于:
byte b = (byte)10;
*/
byte b = /*(byte)*/10;
System.out.println(b);//10
}
}
复制代码
6.3 自增自减运算符
自增、自减运算符是单目运算符,可以放在变量之前,也可以放在变量之后。自增、自减运算符的作用是使变量的值加1或减1。
自增(++)自减(--)运算符
1.作用: 让变量的值增加1(++)或者减少1(--)
2.使用格式:
(1)可以写在变量的前面: ++a,--a
(2)可以写在变量的后面: a++,a--
3.使用特点:
(1)单独使用: ++/--自己独占一行,没有其它运算一起参与
前++和后++,没有任何区别,都是让变量的值增加1
前--和后--,没有任何区别,都是让变量的值减少1
(2)混合使用: 和其它运算(赋值,打印等)一起
前++/--: 先++/--,后再使用 先给变量的值增加(++)或者减少(--)1,然后再使用++/--后的结果
后++/--: 先使用,然后++/-- 先使用变量的值,再把变量的值 增加(++)或者减少(--)1
重点: ----最常用的东西
a++: 变量a的值增加1
a--: 变量a的值减少1
复制代码
例如下图所示:
【示例6】自增自减运算符。示例代码如下:
public class OperatorDemo {
public static void main(String[] args) {
int a = 2;
//++自己独占一行,没有其它运算一起参与
a++;//a = a + 1 = 2 + 1
System.out.println(a);//3
int b = 2;
//++自己独占一行,没有其它运算一起参与
++b;//b = b + 1 = 2 + 1
System.out.println(b);//3
System.out.println("-----------------");
int c = 2;
/*
目前是++和赋值一起操作,属于混合运算
而且++写在了c的前面,先把c的值增加1,
c的值变为3,然后再把结果3赋值给变量d,d的值3
*/
int d = ++c;
System.out.println(c);//3
System.out.println(d);//3
System.out.println("-----------------");
int e = 2;
/*
目前是++和赋值一起操作,属于混合运算
而且++写在了e的后面,所以先使用e的值(2)赋值给变量f,所以f的值是2,
然后e的值再增加1,变成3
*/
int f = e++;
System.out.println(e);//3
System.out.println(f);//2
System.out.println("-----------------");
int x = 4; //5 6
/*
表达式(x++)+(++x)+(x*10)是从左到右计算的
先计算(x++): 因为++在后面,先使用x的值4,然后x的值增加,变成5
4 + (++x)+(x*10)
接着计算(++x): 因为++在前面,先把x的值增加1,x变成6,然后再使用6
4 + 6+(x*10)
接着计算x*10 --> 6*10 结果: 60
4 + 6 + 10 结果: 70
*/
int y = (x++) + (++x) + (x * 10);
// 4 + 6 +
System.out.println(x);//6
System.out.println(y);//70
}
}
复制代码
6.4 关系运算符
关系运算符属于二元运算符,用来判断一个操作数与另外一个操作数之间的关系。不管关系表达式多么复杂或者多么简单,返回值一定是布尔类型的结果,要么是 true,要么是 false,如下表所示:
运 算 符 | 说 明 | 实 例 | 结 果 |
---|---|---|---|
== | 等于 | 2 == 3 | false |
< | 小于 | 2 < 3 | true |
> | 大于 | 2 > 3 | false |
<= | 小于等于 | 5 <= 6 | true |
>= | 大于等于 | 7 >= 7 | true |
!= | 不等于 | 2 != 3 | true |
【示例7】关系运算符。示例代码如下: | |||
“`java | |||
public class OperatorDemo { |
public static void main(String[] args) {
int a = 10, b = 20;
boolean result = (a == b);
System.out.println(result);//false
System.out.println(a != b);//10 != 20: true
System.out.println(a > b);//10 > 20: false
System.out.println(a >= b);//10 >= 20: false
System.out.println(a < b);//10 < 20: true
System.out.println(a <= b);//10 <= 20: true
System.out.println(a == b);//10 == 20: false
System.out.println(a = b);//20 把变量b的值赋值给变量a,最后打印变量a的值
}
复制代码
}
## 6.5 逻辑运算符
假定某面包店,在每周二的下午7点至8点和每周六的下午5点至6点,对生日蛋糕商品进行折扣让利活动,那么想参加折扣活动的顾客,就要在时间上满足这样的条件,(周二并且7:00 PM\~8:00 PM)或者(周六并且5:00 PM\~6:00 PM),这里就用到了逻辑关系。逻辑运算符是对 true(真) 和 false(假) 这两种逻辑值进行运算,运算后的结果仍是一个逻辑值。
```text
用来连接多个条件(布尔表达式的: 结果为true/false的式子),最终的结果也必须是一个布尔类型的数据,要么是true,要么是false
不管逻辑运算符连接的式子有多么简单或者多么复杂,最终结果要么是true,要么是false
分类:
(1) & (shift+7): 逻辑与,表示并且的意思,多个条件同时成立的意思,就是只有多个条件都是true,最终的结果才是true
特点:【有false,则false】: 只要有一个条件不成立(false),结果就是false
(2) |(shift+\): 逻辑或,表示或者的意思,多个条件,只要有一个成立,最终的结果就是true
特点:【有true,则true】:只要有一个条件是true,结果就是true
(2) !(shift+1): 逻辑取反,!true 就是false,!false 就是true
复制代码
【示例8】逻辑运算符。示例代码如下:
public class OperatorDemo {
public static void main(String[] args) {
int a = 10, b = 20, c = 30;
System.out.println(a > b & a > c);//10 > 20 & 10 > 30 ==> false & false ==> false
System.out.println(a < b & a < c);//10 < 20 & 10 < 30 ==> true & true ==> true
System.out.println(a > b & a < c);//10 > 20 & 10 < 30 ==> false & true ==> false
System.out.println(a < b & a > c);//10 < 20 & 10 > 30 ==> true & false ==> false
System.out.println("--------------------");
System.out.println(a > b | a > c);//10 > 20 | 10 > 30 ==> false | false ==> false
System.out.println(a < b | a < c);//10 < 20 | 10 < 30 ==> true | true ==> true
System.out.println(a > b | a < c);//10 > 20 | 10 < 30 ==> false | true ==> true
System.out.println(a < b | a > c);//10 < 20 | 10 > 30 ==> true | false ==> true
System.out.println("--------------------");
System.out.println(a > b ^ a > c);//10 > 20 ^ 10 > 30 ==> false ^ false ==> false
System.out.println(a < b ^ a < c);//10 < 20 ^ 10 < 30 ==> true ^ true ==> false
System.out.println(a > b ^ a < c);//10 > 20 ^ 10 < 30 ==> false ^ true ==> true
System.out.println(a < b ^ a > c);//10 < 20 ^ 10 > 30 ==> true ^ false ==> true
System.out.println("--------------------");
System.out.println(!true);//false
System.out.println(!false);//true
}
}
复制代码
逻辑运算符的短路效果,如下表所示:
运 算 符 | 含 义 | 举 例 | 结 果 |
---|---|---|---|
&& | 逻辑与 | A && B | (真)与(假)= 假 |
|| | 逻辑或 | A || B | (真)或(假)= 真 |
! | 逻辑非 | !A | 不(真)= 假 |
逻辑运算符的运算结果如下表所示: | |||
A | B | A&&B | A||B |
:—– | :—– | :——– | :———- |
true | true | true | true |
true | false | false | true |
false | true | false | true |
false | false | false | false |
说明如下: | |||
“`text | |||
短路逻辑与&&: 左侧为false,右边不计算,短路逻辑或 | : 左侧为true,右侧不计算 | ||
特点: | |||
(1)短路逻辑与&&: 和&结果是相同的,但是&&可以提高效率 | |||
(2)短路逻辑与 | : 和 | 结果是相同的,但是 | 可以提高效率 |
建议: 以后开发学习中,全部使用短路与&& 以及 短路或 | |||
“` | |||
【示例9】逻辑运算符的短路效果。示例代码如下: | |||
“`java | |||
public class OperatorDemo { |
public static void main(String[] args) {
int a = 2;
/*
整个表达式(3>5)&&(++a>2)从左向右计算
先计算表达式3>5结果为false
因为两个表达式使用&&连接,左侧为false,已经决定了最终的结果为false,
不管右侧表达式(++a>2)的结果是true还是false,都无法改变&&的最终结果,
所以右侧表达式(++a>2)不进行计算
*/
System.out.println((3 > 5) && (++a > 2));//false
System.out.println(a);//2: 说明++a没有计算,&&右侧的表达式没有执行
int b = 2;
/*
整个表达式(3>5)&(++b>2)从左向右计算
先计算表达式3>5结果为false
因为两个表达式使用&连接,左侧为false,虽然已经决定了最终的结果为false,
但是右侧表达式(++b>2)仍然要进行计算,所以b的值最终是3
*/
System.out.println((3 > 5) & (++b > 2));//false
System.out.println(b);//3: 说明++b进行计算,&右侧的表达式执行了
System.out.println("-------------------");
int c = 2;
/*
整个表达式(3<5)||(++c>2)从左向右计算
先计算表达式3<5结果为true
因为两个表达式使用||连接,左侧为true,已经决定了最终的结果为true,
不管右侧表达式(++c>2)的结果是true还是false,都无法改变||的最终结果,
所以右侧表达式(++c>2)不进行计算
*/
System.out.println((3 < 5) || (++c > 2));//true
System.out.println(c);//2: 说明++c没有计算,||右侧的表达式没有执行
int d = 2;
/*
整个表达式(3<5)|(++d>2)从左向右计算
先计算表达式3<5结果为true
因为两个表达式使用|连接,左侧为true,虽然已经决定了最终的结果为true,
但是右侧表达式(++d>2)仍然要进行计算,所以d的值最终是3
*/
System.out.println((3 < 5) | (++d > 2));//true
System.out.println(d);//3: 说明++d进行计算,|右侧的表达式执行了
}
复制代码
}
## 6.6 位运算符
位运算的操作数类型是整型,可以是有符号的,也可以是无符号的。位运算符可以分为位逻辑运算符和位移运算符两大类。
| 运 算 符 | 含 义 | 举 例 |
| :-------- | :------------ | :------- |
| & | 与 | a & b |
| \| | 或 | a \| b |
| ~ | 取反 | ~a |
| ^ | 异或 | a ^ b |
| << | 左移位 | a << 2 |
| >> | 右移位 | b >> 4 |
| >>> | 无符号右移位 | x >>> 2 |
位逻辑运算符包括 &、|、^和 ~,前三个是双目运算符,第四个是单目运算符。这四个运算符的运算结果如下表所示:
| A | B | A&B | A\|B | A^B | ~A |
| :---- | :---- | :---- | :---- | :---- | :---- |
| 0 | 0 | 0 | 0 | 0 | 1 |
| 1 | 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 | 0 |
参照上表来看一下这四个运算符的实际运算过程:
```text
1)位逻辑与实际上是将操作数转换成二进制表示方式,然后将两个二进制操作数对象从低位(最右边)到高位对齐,每位求与,
若两个操作数对象同一位都为1,则结果对应位为1,否则结果中对应位为0。例如,12和8经过位逻辑与运算后得到的结果是8。
0000 0000 0000 1100 (十进制12原码表示)
& 0000 0000 0000 1000 (十进制8原码表示)
0000 0000 0000 1000 (十进制8原码表示)
2)位逻辑或实际上是将操作数转换成二进制表示方式,然后将两个二进制操作数对象从低位(最右边)到高位对齐,每位求或,
若两个操作数对象同一位都为0,则结果对应位为0,否则结果中对应位为1。例如,4和8经过位逻辑或运算后的结果是12。
0000 0000 0000 0100 (十进制4原码表示)
| 0000 0000 0000 1000 (十进制8原码表示)
0000 0000 0000 1100 (十进制12原码表示)
3)位逻辑异或实际上是将操作数转换成二进制表示方式,然后将两个二进制操作数对象从低位(最右边)到高位对齐,每位求异或,
若两个操作数对象同一位不同时,则结果对应位为1,否则结果中对应位为0。例如,31和22经过位逻辑异或运算后得到的结果是9。
0000 0000 0001 1111 (十进制31原码表示)
^ 0000 0000 0001 0110 (十进制22原码表示)
0000 0000 0000 1001 (十进制9原码表示)
4)取反运算符,实际上是将操作数转换成二进制表示方式,然后将各位二进制位由1变为0,由0变为1。
例如,123取反运算后得到的结果是-124。
~ 0000 0000 0111 1011 (十进制123原码表示)
1111 1111 1000 0100 (十进制-124原码表示)
复制代码
&、| 和 ^ 也可以用于逻辑运算,运算结果如下表所示:
A | B | A&B | A|B | A^B |
---|---|---|---|---|
true | true | true | true | false |
true | false | false | true | true |
false | true | false | true | true |
false | false | false | false | false |
【示例10】位逻辑运算符的使用场景。示例代码如下: | ||||
“`java | ||||
public class OperatorDemo { |
public static void main(String[] args) {
short x = ~123; // 创建short变量x,等于123取反的值
// 位逻辑与计算整数的结果
System.out.println("12与8的结果为:" + (12 & 8));
// 位逻辑或计算整数的结果
System.out.println("4或8的结果为:" + (4 | 8));
// 位逻辑异或计算整数的结果
System.out.println("31异或22的结果为:" + (31 ^ 22));
// 位逻辑取反计算整数的结果
System.out.println("123取反的结果为:" + x);
// 位逻辑与计算布尔值的结果
System.out.println("2>3与4!=7的与结果:" + (2 > 3 & 4 != 7));
// 位逻辑或计算布尔值的结果
System.out.println("2>3与4!=7的或结果:" + (2 > 3 | 4 != 7));
// 位逻辑异或计算布尔值的结果
System.out.println("2<3与4!=7的与异或结果:" + (2 < 3 ^ 4 != 7));
}
复制代码
}
移位运算有三个,分别是左移 <<、右移>> 和无符号右移 >>>,这三个运算符都属于双目运算符。左移是将一个二进制操作数对象按指定的移动位数向左移,左边(高位端)溢出的位被丢弃,右边(低位端)的空位用0补充。左移相当于乘以2的幂,如下图所示:

例如,short 型整数 9115 的二进制是 0010 0011 1001 1011,左移一位变成 18230,左移两位变成 -29076。

右移是将一个二进制的数按指定的位数向右移动,右边(低位端)溢出的位被丢弃,左边(高位端)用符号位补充,正数的符号位为0,负数的符号为1。右移位运算相当于除以2的幂,如下图所示:

例如 short 型整数 9115 的二进制是 0010 0011 1001 1011,右移一位变成 4557,右移两位变成 2278,运行过程如下图所示:

short 型整数 -32766 的二进制是 0010 0011 1001 1011,右移一位变成 -16383,右移两位变成 -8192,运行过程如下图所示:

无符号右移是将一个二进制的数按指定的位数向右移动,右边(低位端)溢出的位被丢弃,左边(高位端)一律用0填充,运算结果相当于除以2的幂。例如 int 型整数 -32766 的二进制是 1111 1111 1111 1111 1000 0000 0000 0010,右移一位变成 2147467265,右移两位变成 1073733632,运行过程如下图所示:

<font size=3 color=green face=黑体>【示例11】位移运算符的使用场景。示例代码如下:
```java
public class OperatorDemo {
public static void main(String[] args) {
int a = 24;
System.out.println(a + "右移两位的结果是:" + (a >> 2)); //6
int b = -16;
System.out.println(b + "左移三位的结果是:" + (b << 3)); //-128
int c = -256;
System.out.println(c + "无符号右移两位的结果是:" + (c >>> 2)); //1073741760
}
}
复制代码
常见错误:byte、short 类型做 >>> 操作时,可能会发生数据溢出,结果仍为负数。从二进制的实现机制来说,byte 类型和 short 类型不适用于 >>> 操作。
【示例12】byte和short做无符号右移产生的问题。示例代码如下:
public class OperatorDemo {
public static void main(String[] args) {
byte a = (byte) (-32 >>> 1);
System.out.println("byte无符号右移的结果:" + a); //-16
short b = (short) (-128 >>> 4);
System.out.println("short无符号右移的结果:" + b); // -8
}
}
复制代码
6.7 三元运算符
1.格式:
数据类型 变量名称 = 布尔表达式1 ? 表达式2 : 表达式3;
2.执行流程:
(1)计算布尔表达式1的结果,看是true还是false
(2)如果布尔表达式1的结果为true,就把表达式2的结果赋值给左侧的变量
(3)如果布尔表达式1的结果为false,就把表达式3的结果赋值给左侧的变量
复制代码
执行流程图解:
【示例13】用三元运算符完成判断一个数字的奇偶性。示例代码如下:
import java.util.Scanner;
public class OperatorDemo {
public static void main(String[] args) {
int iInput;
Scanner sc = new Scanner(System.in); // 创建扫描器
System.out.println("Input number");
iInput = sc.nextInt(); // 控制台输入一个数字
System.out.println(iInput % 2 != 0 ? "这个数是奇数" : "这个数是偶数");
}
}
复制代码
【示例14】使用条件表达式判断一个数是否是3和5的公倍数。示例代码如下:
import java.util.Scanner;
public class OperatorDemo {
public static void main(String[] args) {
int iInput;
Scanner sc = new Scanner(System.in); // 创建扫描器
System.out.println("Input number");
iInput = sc.nextInt(); // 控制台输入一个数字
// 使用嵌套的运算符,先判断是否可以整除3,如果可以整除3,再判断是否可以整除5
boolean bool = iInput % 3 == 0 ? ((iInput % 5 == 0) ? true : false) : false;
System.out.println("这个数是3和5的公倍数吗?" + bool);
}
}
复制代码
【示例15】三元运算符的练习之两只老虎(相等)。示例代码如下:
public class OperatorDemo {
/*需求:
动物园里有两只老虎,已知两只老虎的体重分别为180kg、200kg,
请用程序实现判断两只老虎的体重是否相同。
实现步骤:
1.定义两个int变量w1和w2,分别代表两只老虎的体重,并按照题目要求进行初始化
2.使用三元运算符判断w1和w2的值是否相同,保存到boolean变量result中
3.打印result的值*/
public static void main(String[] args) {
//1.定义两个int变量w1和w2,分别代表两只老虎的体重,并按照题目要求进行初始化
int w1 = 180, w2 = 200;
//2.使用三元运算符判断w1和w2的值是否相同,保存到boolean变量result中
boolean result = (w1 == w2) ? true : false;
//3.打印result的值
System.out.println("两只老虎的体重相同吗? " + result);
System.out.println("---------------");
String s = (w1 == w2) ? "相同" : "不相同";
System.out.println("两只老虎的体重相同吗? " + s);
}
}
复制代码
【示例16】三元运算符的练习之两只老虎(最大值)。示例代码如下:
public class OperatorDemo {
/*需求:
动物园里有两只老虎,已知两只老虎的体重分别为180kg、200kg,
请用程序实现计算两只老虎的体重的最大值。
实现步骤:
1.定义两个int变量w1和w2,分别代表两只老虎的体重,并按照题目要求进行初始化
2.使用三元运算符,计算w1和w2的最大值,把结果保存到int变量max中
3.打印max的值*/
public static void main(String[] args) {
//1.定义两个int变量w1和w2,分别代表两只老虎的体重,并按照题目要求进行初始化
int w1 = 180, w2 = 200;
//2.使用三元运算符,计算w1和w2的最大值,把结果保存到int变量max中
int max = (w2 > w1) ? w2 : w1;
//3.打印max的值
System.out.println("两只老虎体重的最大值: " + max);
}
}
复制代码
图解分析:
【示例17】三元运算符的练习之三个和尚。示例代码如下:
public class OperatorDemo {
/*需求:
一座寺庙里住着三个和尚,已知他们的身高分别为150cm、210cm、165cm,
请用程序实现获取这三个和尚的最高身高。
实现步骤:
1.定义3个int变量h1,h2,h3代表三个和尚的身高,并根据题目需求进行初始化
2.使用三元运算符计算出h1和h2的最大值,保存到int变量temp中
3.使用三元运算符计算出temp和h3的最大值,保存到int变量max中
4.最终打印max的值*/
public static void main(String[] args) {
//1.定义3个int变量h1,h2,h3代表三个和尚的身高,并根据题目需求进行初始化
int h1 = 150, h2 = 210, h3 = 165;
//2.使用三元运算符计算出h1和h2的最大值,保存到int变量temp中
int temp = (h1 > h2) ? h1 : h2;
//3.使用三元运算符计算出temp和h3的最大值,保存到int变量max中
int max = (temp > h3) ? temp : h3;
//4.最终打印max的值
System.out.println("三个和尚的最大身高: " + max);//210
}
}
复制代码
图解分析:
6.8 圆括号
圆括号可以提升公式中计算过程的优先级,在编程中非常常用。如下图所示,使用圆括号更改运算的优先级,可以得到不同的结果。
圆括号还有调整代码格式,增强阅读性的功能。比如下面的这个公式:
a = 7 >> 5 * 6 ^ 9 / 3 * 5 + 4;
/*这样的计算公式复杂且难读,如果稍有疏忽就会估错计算结果,影响后续代码的设计。
但是要把刚才的计算公式加上圆括号,且不改变任何运算的优先级,改为如下代码:*/
a = (7 >> (5 * 6)) ^ ((9 / 3 * 5) + 4); //这行代码的运算结果没有发生任何改变,但运算逻辑却显得非常清晰。
复制代码
6.9 运算符优先级
Java 中的表达式就是使用运算符连接起来并且符合 Java 规则的式子。运算符的优先级决定了表达式中运算的先后顺序。通常优先级由高到低的顺序依次是:自增和自减运算、算术运算、位运算、逻辑运算、赋值运算。如果两个运算有相同的优先级,会以从左到右的方式进行运算。下表显示 Java 中的运算符的优先级。
优先级 | 描 述 | 运 算 符 | 说 明 |
---|---|---|---|
1 | 圆括号 | () | 优先计算圆括号里代码 |
2 | 自增,自减,逻辑非,正号,负号,取反 | ++ — ! + – ~ | 优先计算导致变量自身改变的运算符 |
3 | 乘,除,取余 | * / % | 算术优先乘除法,同级从左到右 |
4 | 加,减 | + – | 乘除之后计算加减法,同级从左到右 |
5 | 左移位,右移位,无符号右移位 | << >> >>> | 同级从左到右 |
6 | 小于,小于等于,大于,大于等于,判断继承关系 | < <= > >= instanceof | 同级从左到右 |
7 | 等于,不等于 | == != | 同级从左到右 |
8 | 与 | & | 同级从左到右 |
9 | 异或 | ^ | 同级从左到右 |
10 | 或 | | | 同级从左到右 |
11 | 逻辑与 | && | 同级从左到右 |
12 | 逻辑或 | || | 同级从左到右 |
13 | 赋值 | = += -= *= /= %= <<= >>= &= ^= |= >>>= | 最后赋值 |