Appearance
Java 基础语法
标识符
什么是标识符
- 在 Java 中,标识符是用来给变量、方法、类和包等命名的字符序列。
- 标识符的长度没有限制,但是建议使用有意义的、简洁的标识符,以提高代码的可读性和可维护性。
标识符可以标识什么
- 变量名
- 方法名
- 类名、接口名、枚举名、注解名
- 包名
- 常量名
- ......
标识符命名规则
- 标识符可以由字母、数字、下划线(_)和美元符号($)组成,不能含有其他符号。(java 支持全球所有语言,所以这里的字母 指的是任何一个国家的文字都可以)
- 标识符不能以数字开头。
- 标识符不能是 Java 中的关键字,如 public、class、void 等。
- 标识符是区分大小写的,即 Foo 和 foo 是两个不同的标识符。
- 标识符的长度没有限制,但是 Java 建议使用有意义的、简短的标识符。
标识符命名规范
- 见名知意
- 驼峰式命名方式
- 类名、接口名、枚举、注解:首字母大写,后面每个单词首字母大写。(StudentService,UserService)
- 变量名和方法名:首字母小写,后面每个单词首字母大写。(doSome,doOther)
- 常量名:全部大写,每个单词用下划线连接。(LOGIN_SUCCESS,SYSTEM_ERROR)
- 包名:全部小写
判断标识符是否合法
- myVariable
- 2name
- first.name
- studentName
- public
- public1
- address#
- MAX_SIZE
- id#
- _id
- @age
- $money
- 你好
关键字
什么是关键字
- Java 关键字是 Java 编程语言中预定义的具有特殊含义的单词,这些单词不能被用作标识符,而是在语法中有特定的用法和限制。
Java 关键字有哪些
- Java 关键字都是小写的。
- abstract, assert, boolean, break, byte, case, catch, char, class, continue, default, do, double, else, enum, extends, final, finally, float, for, if, implements, import, instanceof, int, interface, long, native, new, package, private, protected, public, return, short, static, strictfp, super, switch, synchronized, this, throw, throws, transient, try, void, volatile, while
- Java 保留字:goto,const
字面量
什么是字面量
- 字面量指的是在程序中直接使用的数据,字面量是 Java 中最基本的表达式,不需要进行计算或转换,直接使用即可。
Java 中有哪些字面量
- 整数型:10、-5、0、100
- 浮点型:3.14、-0.5、1.0
- 布尔型:true、false
- 字符型:'a'、'b'、'c'、'1'、'2'、'国'
- 字符串型:"Hello"、"World"、"Java"、"你好呀"
加号运算符 +
- 作用 1:求和(当加号两边都是数字时进行求和运算)
- 作用 2:字符串拼接(当加号两边有任意一边是字符串类型时会进行字符串拼接,结果还是一个字符串)
变量
什么是变量?
- 变量是内存当中的一块空间。是计算机中存储数据最基本的单元。
- 变量三要素:
- 数据类型(决定空间大小)【int, double, String】
- 变量名(只要是合法的标识符即可)
- 变量值(变量中具体存储的数据)
- 变量的声明、赋值、访问
- int i; // 声明一个整数型的变量,起名 i
- i = 100; // 给变量 i 赋值 100
- System.out.println(i); // 访问 i 变量:读操作
- i = 200; // 访问 i 变量:改操作【给变量 i 重新赋值 200】
变量的作用
- 变量的存在会让程序更加便于维护。
- 变量的存在可以增强程序的可读性。
System.out.println(100 + 111);
System.out.println(100 + 222);
以上代码的设计就不如以下的代码:
int num = 100;
System.out.println(num + 111);
System.out.println(num + 222);
System.out.println(3.14 _ 10 _ 10);
以上代码的设计就不如以下的代码:
double π = 3.14;
int r = 10;
System.out.println(π _ r _ r);
变量的小细节
- 变量必须先声明,再赋值,才能访问
- 方法体当中的代码遵循自上而下的顺序依次逐行执行,变量先访问,再声明肯定是不行的
- 一行代码上可以同时声明多个变量
- 在同一个作用域当中,变量名不能重名,可以重新赋值
- 变量值的数据类型必须和变量的数据类型一致,这样是不允许的:String name = 100;
变量的作用域
- 作用域就是变量的有效范围。变量的作用域是怎样的呢?用一句大白话就可以概括了:出了大括号就不认识了。
- 作用域的不同主要是因为声明在不同位置的变量具有不同的生命周期。所谓的生命周期是:从内存开辟到内存释放。
- Java 遵循就近原则
变量的分类
- 局部变量
- 成员变量
- 静态变量
- 实例变量
二进制
二进制概述
- 计算机底层只能识别二进制。计算机底层只识别二进制是因为计算机内部的电子元件只能识别两种状态,即开和关,或者高电平和低电平。二进制正好可以用两种状态来表示数字和字符,因此成为了计算机最基本的表示方法。在计算机内部,所有的数据都被转化为二进制形式进行处理和存储。虽然计算机可以通过不同的编程语言和程序来处理不同的数据类型和格式,但最终都需要将其转化为二进制形式才能被计算机底层识别和处理。
什么是二进制
- 十进制:满十进一
- 二进制:满二进一
十进制转换为二进制
- 将十进制数除以 2,得到商和余数。
- 将余数记录下来,然后将商作为新的十进制数,重复步骤 1,直到商为 0 为止。
- 将记录的余数从下往上排列,得到的就是对应的二进制数。
二进制转换为十进制
- 将二进制数每一位权值找出来,然后每个权值与对应二进制位相乘,最后将它们相加,即可得到十进制数。
- 什么是权值?
- 例如,二进制数 1101 转换为十进制数的计算过程如下:
在二进制中,权值指的是每个位所代表的数值大小,即二进制中每个位的位置所代表的数值大小。例如,在二进制数 1101 中,最高位的权值为 8,次高位的权值为 4,第三位的权值为 2,最低位的权值为 1。
1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 8 + 4 + 0 + 1 = 13
练习一下:
- 将以下十进制的数字转换为二进制:
- 将以下二进制的数字转换为十进制:
243
165
89
101010
111100
011001
八进制与十六进制
什么是八进制
- 满八进一
十进制转换为八进制
- 与二进制原理相同
八进制转换为十进制
- 与二进制原理相同
什么是十六进制
- 满十六进一
十进制转换为十六进制
- 与二进制原理相同
十六进制转换为十进制
- 与二进制原理相同
二进制转换为十六进制
- 将二进制数从右往左每四位一组,不足四位则在左侧补 0,得到若干个四位二进制数。
- 将每个四位二进制数转换为对应的十六进制数
十六进制转换为二进制
- 将十六进制中的每个数字转换成 4 个二进制位
原码反码补码
byte 与 bit
- byte(字节)是计算机存储和处理数据的基本单位,通常由 8 个比特(bit)组成。每个比特(bit)是计算机中最小的存储单位,只能存储 0 或 1 两个状态。因此,一个字节(byte)可以存储 8 个比特(bit)的数据。
- 两者之间的关系是,1 byte = 8 bit,即 8 个比特(bit)组成一个字节(byte)。
- 在计算机中,数据通常以字节(byte)为单位进行存储和传输,而比特(bit)则是用来表示数据的最小单位。
- 1KB = 1024byte
- 1MB = 1024KB
- 1GB = 1024MB
- 1TB = 1024GB
原码反码补码
- 原码反码补码是计算机二进制的三种表示形式。
- 计算机在底层都是采用二进制补码形式表示的。
- 二进制位最高位称为符号位,0 为正数,1 为负数。
正数的原码反码补码
- 正数的原码反码补码是相同的。
- 请问 127 的原码反码补码分别是多少?0111 1111
负数的原码反码补码
- 负数的原码运算规则:将绝对值转换为二进制后,最高位改为 1。
- -5 的原码:10000101
- -5 的反码:11111010(原则是:以原码作为参考,符号位不变,其他位取反。)
- -5 的补码:11111011(原则是:以反码作为参考,符号位不变,加 1)
- 请问-20 的原码反码补码是多少?
- 请问-128 的原码反码补码是多少?
已知负数补码怎么得到原码
- 虽然计算机底层是采用补码的形式存储的,但最终显示给人类的时候是以原码的形式显示的。所以大家需要具备这个能力!!!
- 将负数的补码形式除符号位外的所有位按位取反,再加 1 即可得到原码。
- 已知补码:10000001
- 它的原码是:11111111
- 结果是:-127
- 通过这个可以得出,对于一个字节来说,最大值 127,最小值-128。
计算机底层为什么采用补码
- 可以简化电路设计:采用补码形式可以将加减法运算转化为相同的操作,从而简化电路设计。
- 解决了 0 的正负问题:在原码中,0 有两个表示,+0 和-0,这样会导致计算结果不唯一,而在补码中,0 只有一种表示,即全 0,可以避免这个问题。
- 解决了负数溢出问题:在原码中,负数的表示范围比正数少 1,这样在进行减法运算时容易出现负数溢出的情况,而在补码中,负数的表示范围与正数相同,可以避免负数溢出的问题。
- 方便计算机进行运算:补码形式可以方便计算机进行加减法运算,而且可以使用相同的电路进行运算,从而提高了计算机的运算效率。
- 可以计算一下 -3 + 2,看看能不能理解!!!
数据类型
概述
1.数据类型作用?
决定给变量分配多大的空间。
2.为什么要学习数据类型?
为了定义变量。
3.整数型定义那么多干嘛?
关于默认值:Java 语言中变量必须先声明,再赋值,才能使用。对于局部变量来说必须手动赋值,而对于成员变量来说,如果没有手动赋值,系统会自动赋默认值。
整数型详解
整数型字面量的四种表示形式
- 十进制表示法:以数字 0-9 组成的常数,默认为十进制表示法。
例如:int a = 10; - 二进制表示法:以 0b 或 0B 开头的常数,由 0 和 1 组合而成。
例如:int b = 0b101; - 八进制表示法:以 0 开头的常数,由数字 0-7 组成。
例如:int c = 012; - 十六进制表示法:以 0x 或 0X 开头的常数,由 0-9 和 A-F(大小写均可)组成。
例如:int d = 0x1F;
整数型字面量默认当做 int 处理
- Java 中整数型字面量默认被当做 int 类型来处理,如果要表示 long 类型的整数,需要在字面量后面加上'L'或'l'标记。例如,下面是表示 int 和 long 类型整数的字面量的示例:
- 请看以下代码有什么问题吗?
int x = 10; // 10 是一个 int 类型的字面量
long y = 10L; // 10L 是一个 long 类型的字面量
需要注意的是,大小写字母'L'和'l'的使用没有区别,但是容易被误解为数字 1,因此建议使用大写字母。
long z = 2147483648;
编译报错,原因是 2147483648 被当做 int 类型处理,而该数字本身已经超出了 int 最大值,如何修改?
long z = 2147483648L;
自动类型转换
- 在 Java 中,对于基本数据类型来说,小容量是可以直接赋值给大容量的,这被称为自动类型转换。对于数字类型来说大小关系为:byte < short < int < long < float < double
强制类型转换
- Java 中大容量是无法直接转换成小容量的。因为这种操作可能会导致精度损失,所以这种行为交给了程序员来决定,当然这种后果自然是程序员自己去承担。因此在代码中需要程序员自己亲手加上强制类型转换符,程序才能编译通过
- 强制类型转换时,底层二进制是如何变化的?原则:砍掉左侧多余的二进制。
- 强制类型转换时,精度可能会损失,也可能不会损失,这要看具体的数据是否真正的超出了强转后的类型的取值范围。如下图:水可能溢出,也可能不会溢出,这要看真实存放的水有多少
- 请推算结果:byte b = (byte)150;
当整数字面量没有超出 byte 的范围
- 在 Java 中有这样一个规定,当整数型字面量没有超出 byte 的范围:可以直接赋值给 byte 类型的变量。
- 如果超出了范围,例如:
- 在整数类型中,除了 byte 有这个待遇之外,short 同样也是支持的。也就是说:如果整数型字面量没有超出 short 取值范围时,也是支持直接赋值的。
byte b = 127; // 这是允许的
很显然,这是一种编译优化。同时也是为了方便程序员写代码。
byte b = 128; // 编译报错
这样就会报错,需要做强制类型转换,例如:
byte b = (byte)128;
它的执行结果你知道吗?可以尝试推算一下
两个 int 类型做运算
- 两个 int 类型的数据做运算,最终的结果还是 int 类型
多种数据类型混合运算
- 在 Java 中,多种数据类型混合运算时,各自先转换成容量最大的类型,再做运算
byte a = 100;
int b = 200;
long c = 300L;
long d = a + b + c;
你可以测试一下,如果 d 变量是 int 类型则编译器会报错
编译器的小心思
- 以下程序编译通过:
- 以下程序编译报错:
- 怎么解决?要么把 x 变量声明为 int 类型,要么强制类型转换,例如:
byte x = 10 / 3;
为什么编译通过?这种情况下都是字面量的时候,编译器可以在编译阶段得出结果是 3,而 3 没有超出 byte 取值范围。可以直接赋值。
int a = 10;int b = 3;byte x = a / b;
为什么编译失败?这种 a 和 b 都是变量的情况下,编译器是无法在编译阶段得出结果的,编译器只能检测到结果是 int 类型。int 类型不能直接赋值给 byte 类型变量。
int a = 10;int b = 3;byte x = (byte)(a / b);
这里需要注意的是:注意小括号的添加,如果不添加小括号,例如:
int a = 10;int b = 3;byte x = (byte)a / b;
这样还是编译报错,因为只是将 a 强转为 byte 了,b 还是 int。byte 和 int 混合运算,结果还是 int 类型。
浮点型详解
浮点型字面量默认被当做 double
- Java 中,浮点型字面量默认被当做 double 类型,如果要当做 float 类型,需要在数字后面添加 F 或 f。
- 另外,可以通过以下程序的输出结果看到,double 精度高于 float:
float f = 3.0; // 编译报错
报错原因是:3.0 默认被当做 double 类型,大容量无法直接赋值给小容量。如何修改:
float f = 3.0F;
double d = 1.5656856894;
System.out.println(d);
float f = 1.5656856894F;
System.out.println(f);
浮点型数据两种表示形式
- 第一种形式:十进制
- 第二种形式:科学计数法
double x = 1.23;
double y = 0.23;
double z = .23;
double x = 0.123E2; // 0.123 _ 10 的平方
double y = 123.34E-2; // 123.34 / 10 的平方
浮点型数据存储原理
- 符号位:0 表示整数。1 表示负数。
- 指数位:比如小数 0.123E30,其中 30 就是指数。表示 0.123 \_ 10 的 30 次幂。所以也有把指数位叫做偏移量的。最大偏移量 127。
- 尾数位:浮点数的小数部分的有效数字。例如:0.00123,那么尾数位存储 123 对应的二进制。
- 从浮点型数据存储原理上可以看到,二进制中的指数位决定了数字呈指数级增大。因此 float 虽然是 4 个字节,但却可以表示比 long 更大的数值。因此 float 容量比 long 的容量大。
浮点型数据使用注意事项
- 一旦有浮点型数据参与运算得出的结果,一定不要使用“==”与其它数字进行“相等比较”
- 不要这样:
- 可以这样:
java
double x = 6.9;
double y = 3.0;
double z = x / y;
if(z == 2.3){
System.out.println("相等");
}
java
double x = 6.9;
double y = 3.0;
double z = x / y;
if(z - 2.3 < 0.000001){
System.out.println("相等");
}
字符型详解
字符型 char
- 占用两个字节,0~65535,和 short 容量相同,但 char 可以取更大的整数
- 单个字符,使用单引号括起来,不能是多个字符
- 可以保存一个汉字
- char c = ‘’; 这是不允许的
- char c = ‘\u0000’; 这表示一个空字符,也是 char 的默认值。\u0000 是一个 Unicode 码。
- 空字符与空格字符是不同的。空字符表示什么也没有。空格字符表示一个空格。
转义字符
- \t: 表示制表符,相当于按下 Tab 键
- \n: 表示换行符
- \": 表示双引号(")
- \': 表示单引号(')
- \\: 表示反斜线(\)本身
字符编码
- 字符编码是人为规定的文字与二进制之间的转换关系。
- 在早期计算机系统中,字符编码主要采用的是 ASCII 编码,采用 1 个字节编码。最多可以表示 256 个字符。(实际上 ASCII 码表只用了 128 个。),程序员需要记住这几个:
a 对应 ASCII 码 97(b 是 98,以此类推)
A 对应 ASCII 码 65(B 是 66,以此类推)
0 对应 ASCII 码 48(1 是 49,以此类推)
什么是编码?什么是解码?乱码是怎么产生的?
- 字符在计算机系统中,解码(Decoding)和编码(Encoding)是两个常用的概念,分别表示将二进制数据转换为字符和将字符转换为二进制数据。
- 编码是将字符转换为二进制数据的过程。解码是将二进制数据转换为字符的过程。例如:
- 乱码是指在字符编码和解码的过程中,由于编码和解码所采用的字符集不一致,或者编码和解码所采用的字符集不支持某些字符,导致最终显示的字符与原始字符不一致。为了避免乱码的问题,我们需要统一使用一个字符集,并且在进行字符编码和解码时要保持一致。
'a' -------- 按照 ASCII 码表编码 -------- > 01100001
01100001 -------- 按照 ASCII 码表解码 -------- > 'a'
常见的字符编码
- ASCII 编码(American Standard Code for Information Interchange:美国信息交换标准编码):采用 1 个字节编码,包括字母、数字、符号和控制字符等。
- Latin-1 编码(ISO 8859-1),采用 1 个字节编码。该编码方式是为了表示欧洲语言(如荷兰语、西班牙语、法语、德语等)中的字符而设计的,共支持 256 个字符。
- ANSI 编码(American National Standards Institute:美国国家标准协会):采用 1 个字节编码,支持英文、拉丁文等字符。两个 ANSI 码可以表示一个汉字。
- Unicode 编码:可表示所有语言的字符。采用了十六进制表示,占用 2 个字节或 4 个字节,最多可表示超过一百万个字符。 (使用这种方式是有点浪费空间的,例如英文字符'a'其实采用一个字节存储就够了。)
- UTF-8 编码(Unicode Transformation Format,8-bit):基于 Unicode 编码的可变长度字符编码,能够支持多语言和国际化的需求,使用 1~4 个字节来表示一个字符,是目前 Web 开发中最常用的字符编码方式。(一个英文字母 1 个字节,一个汉字 3 个字节。)
- UTF-16 编码:基于 Unicode 编码的可变长度字符编码,使用 2 或 4 个字节来表示一个字符,应用于很多较早的系统和编程语言中。 (一个英文字母 2 个字节。一个汉字 4 个字节。)
- UTF-32 编码:基于 Unicode 编码的固定长度字符编码,其特点是每个字符占用 4 个字节。
常见的字符编码
- GB2312 编码(小):是中国国家标准的简体中文字符集,使用 2 个字节来表示一个汉字,是 GBK 编码的前身。
- GBK 编码(Guo Biao Ku)(中):是针对中文设计的一个汉字编码方式,使用 2 个字节来表示一个汉字,能够表示中国内地的所有汉字。
- GB18030 编码(大):是中国国家标准 GB 18030-2005《信息技术 中文编码字符集》中规定的字符集编码方案,用于取代 GB2312 和 GBK 编码。
- Big5 编码(大五码):是台湾地区的繁体中文字符集,使用 2 个字节来表示一个汉字,适用于使用繁体中文的应用场景。
每种编码方式都有其特点和适用场景。在进行软件开发、网站开发和数据存储时,需要根据实际情况选择适合的编码方式。
Unicode 码表的一部分
- 网络上也有很多在线转码工具,例如:http://www.jsons.cn/unicode/
char 参与的运算
- Java 中允许将一个整数赋值给 char 类型变量,但这个整数会被当做 ASCII 码值来处理
- 需要特别注意的是,这个码值有要求,不能超出 char 的取值范围
- 只要没有超出 byte short char 的取值范围,是可以直接赋值给 byte short char 类型变量的
- System.out.println('a' + 1);结果是什么?
- char c = 'a' + 1;结果是什么?
- 以下程序结果是什么?
- byte short char 混合运算时,各自会先转换成 int 再做运算!!!!!
byte b = 1;
short s = 1;
char c = 1;
short num = b + s + c;
布尔型
boolean 类型
- boolean 类型只有两个值:true、false。没有其它值,没有 0 和 1 这一说。
- 通常用于表示一些逻辑上的真假值,并在程序中进行逻辑控制,例如以下代码:
java
boolean gender = true;
if(gender){
System.out.println("男");
}else{
System.out.println("女");
}
基本数据类型转换规则
八种基本数据类型,除布尔型之外,其它类型都可以互相转换。
小容量转换为大容量,叫做自动类型转换,容量从小到大的排序为:
a. byte < short(char) < int < long < float < double
b. 注意 char 比 short 可以表示更大的整数
大容量转换为小容量,叫做强制类型转换,需要加强制类型转换符才能编译通过,运行时可能损失精度,也可能不会损失。
整数字面量如果没有超出 byte short char 的取值范围,可以直接赋值给 byte short char 类型的变量。
byte short char 混合运算,各自先转换为 int 再做运算。
多种类型混合运算,各自先转换成容量最大的类型,再做运算。
作业题
1.请定义合理的变量用来存储个人信息(姓名、年龄、性别、联系电话),并编写程序定义这些变量,给变量赋值,并打印输出。输出效果如下
姓名 年龄 性别 联系电话 张三 20 男 12545457585 李四 30 女 15622525855
2.有两个变量 a 和 b,a 变量中存储的数据 100,b 变量中存储的数据 200,请编写程序交换两个变量中的数据。让 a 变量存储 200,让 b 变量存储 100。并且计算两个 int 类型数据的和,要求最终输出 200+100=300 的效果。
3.请分析以下程序中哪些是可以编译通过的,哪些是报错的
java
short s = 100;
s = s - 99;
byte b = 100;
b = b + 1;
char c = 'a';
int i = 20;
float f = .3F;
double d = c + i + f;
byte b1 = 11;
short s1 = 22;
short x = b1 + s1;
运算符
- 算术运算符:+、-、*、/、%、++、--
- 关系运算符:==、!=、>、>=、<、<=
- 逻辑运算符:&、|、!、&&、||
- 按位运算符:&、|、^、~、<<、>>、>>>
- 赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=、>>>=
- 条件运算符:?:
- instanceof 运算符:instanceof
- new 运算符:new
- .运算符:.
注意:运算符有优先级,关于优先级不需要记忆,不确定的添加小括号,添加小括号的优先级高,会先执行
算术运算符
算术运算符
- + :求和、字符串拼接、正数
- - :相减、负数
- * :乘积
- / :商(除法)
- % :取模(求余数)
- 取模公式:x - x / y * y
- ++ :自加 1
- -- :自减 1
接收用户键盘输入
java
java.util.Scanner scanner = new java.util.Scanner(System.in);
String s1 = scanner.next();
String s2 = scanner.nextLine();
int i = scanner.nextInt();
double d = scanner.nextDouble();
栈数据结构(Stack)
- 栈结构特点:
- 先进后出
- 后进先出
- 相关术语:
- 入栈、压栈、push
- 出栈、弹栈、pop
- 栈帧
- 栈顶、栈底
字节码解读
- 查看字节码的命令:javap -c 字节码文件
- 查看以下程序的字节码
- 字节码指令:
- 什么是局部变量表和操作数栈?
java
public class ReadClass{
public static void main(String[] args){
int i = 10;
int j = i;
j++;
}
}
查看字节码:javap -c ReadClass.class
bipush 指令:将字面量压入操作数栈
istore_1 指令:将操作数栈中顶部数据弹出,然后将该数据存放到局部变量表的第 1 个位置
iload_1 指令:将局部变量表 1 号槽位的数据压入操作数栈
iinc 指令:将局部变量表中第 1 个位置数据加 1
算术运算符作业
- 题目 1:采用字节码解读的方式分析以下代码的区别
- 题目 2:以下程序输出结果是?
- 题目 3:以下程序输出结果是?
- 题目 4:以下程序输出结果是?经典面试题
- 题目 5:从键盘上接收一个整数三位数,请分别输出它的个位、十位、百位。
- 题目 6:681 分钟是多少个小时+多少分钟。
int i = 10;
int k = i++;
int i = 10;
int k = ++i;
int a = 5;
int b = a++;
b = a++;
System.out.println("a = " + a);
System.out.println("b = " + b);
int c = 10;
int d = --c;
System.out.println("c = " + c);
System.out.println("d = " + d);
int i = 10;
int k = i++ + ++i;
System.out.println(k);
int f = 10;
int m = f++ +f;
System.out.println(m);
System.out.println(f);
int i = 10;
i = i++;
System.out.println(i);
int i = 10;
i = ++i;
System.out.println(i);
关系运算符
- 关系运算符又叫做比较运算符。包括:>、 >=、 <、 <=、 ==、 !=
- 所有关系运算符的运算结果都是布尔类型,不是 true,就是 false。
int a = 10;
int b = 10;
System.out.println(a > b); // false
System.out.println(a >= b); // true
System.out.println(a < b); // false
System.out.println(a <<= b); // true
System.out.println(a == b); // true
System.out.println(a != b); // false
逻辑运算符
- 逻辑运算符:&(逻辑与)、 |(逻辑或)、 !(逻辑非)、^(逻辑异或)、 &&(短路与)、||(短路或)
- 逻辑运算符特点:逻辑运算符两边的操作数要求必须是布尔类型,并且最终运算结果也一定是布尔类型。
- 逻辑与&:两边操作数都是 true,结果才是 true。可以翻译为“并且”。
- 逻辑或|:两边操作数只要有一个是 true,结果就是 true。可以翻译为“或者”。
- 逻辑非!: !false 就是 true,!true 就是 false。
- 逻辑异或^:咱俩不一样,结果就是 true。
- 短路与&&:和逻辑与&的运算结果相同。只是存在一种短路现象。(左边操作数为 false 时,右边操作数不执行)
- 短路或||:和逻辑或|的运算结果相同。只是存在一种短路现象。(左边操作数为 true 时,右边操作数不执行)
- 虽然短路与&&效率高于逻辑与&,但逻辑与&也有用武之地,具体看需求是怎样的。
按位运算符
按位运算符
- 按位运算符用于在二进制位级别上处理整数数据。主要包括:
- 左移 <<
- 右移 >>
- 无符号右移 >>>
- 按位与 &
- 按位或 |
- 按位异或 ^ l 按位取反 ~
- 注意:按位运算符的操作数要求必须是整数。否则会出现编译错误
左移 <<
- 它能够将一个二进制数的所有位向左移动指定的位数。左移运算符的运算规则如下:
将二进制数左移 n 位,相当于将数值乘以 2 的 n 次方。
例如,将二进制数 0b1011 左移 2 位,即为 0b101100,相当于将 11 乘以 2 的 2 次方(即 4),得到 44。
左移运算符不会改变操作数的符号。左移后,右补 0。
无论操作数是正数、负数还是零,左移运算符都只进行位级移动,不会改变符号。
左移运算符会对溢出进行截断。
- 应用一下:如何将 2 快速变成 8?
右移 >>
它能够将一个二进制数的所有位向右移动指定的位数。右移运算符的运算规则如下:
- 将二进制数右移 n 位,相当于将数值除以 2 的 n 次方。
例如,将二进制数 0b101100 右移 2 位,即为 0b1011,相当于将 44 除以 2 的 2 次方(即 4),得到 11。
- 右移运算符对正数、负数和零的处理方式不同。
对于正数,符号位不变,右移时左补 0
对于负数,符号位不变,右移时左补 1。
对于零,右移运算符操作后结果仍为零。
- 右移运算符会对溢出进行截断。
无符号右移 >>>
它能够将一个二进制数的所有位向右移动指定的位数,而不考虑符号位。无符号右移运算符的运算规则如下:
将二进制数右移 n 位,相当于将数值除以 2 的 n 次方,并将最高位填充为 0。
任意一个数字经过无符号右移之后,最终结果一定是非负数(0 或正整数)
无符号右移运算符对溢出进行截断。
按位与 &
- 将两个整数的二进制表示按位进行与运算,只有当相应的二进制位都为 1 时,结果才为 1,否则结果为 0
- 应用一下:请使用按位与运算符判断某个数字是否为奇数?思路:拿着这个数字和 1 进行按位与,如果结果是 1,则表示该数字为奇数。
int a = 32;
int b = 25;
System.out.println(a & b); // 0
a 的二进制:00100000
b 的二进制:00011001
按位与之后:00000000
按位或 |
- 将两个整数的二进制表示按位进行或运算,只有当相应的二进制位都为 0 时,结果才为 0,否则结果为 1
- 应用一下:请将 0 这个数字中第 4 位的二进制位设置为 1(按位或的具体应用,将某个二进制位设置为 1)
int a = 32;
int b = 25;
System.out.println(a | b); // 57
a 的二进制:00100000
b 的二进制:00011001
按位或之后:00111001
int flag = 0;
flag = flag | (1 << 3);
按位异或 ^
- 将两个整数的二进制表示按位进行异或运算,只有当相应的二进制位不同,结果才为 1,否则结果为 0
- 按位异或运算符具有自反性,所谓的自反性是指:数字 A 连续对数字 B 进行两次按位异或运算之后,可以得到原始的数字 A。因为按位异或运算符具有这样的特征,所以在密码学方面应用广泛。通常使用它可以完成加密和解密操作。
- 应用一下:按位异或可以实现简单的加密和解密。
int a = 100;
int b = 200;
System.out.println(a ^ b); // 172
a 的二进制:01100100
b 的二进制:11001000
按位异或之后:10101100
按位取反 ~
- 将整数的二进制表示按位进行取反运算,即 0 变为 1,1 变为 0
- 应用一下:位清除操作(将某个二进制位中指定位清除为 0),例如有这样一个二进制:0b01101101,将第 4 个低位清除为 0
System.out.println(~100); // -101
100 的二进制:01100100
取反后:10011011(这是一个补码哦)
将补码转为原码:11100101 (-101)
int value = 0b01101101;// 待清除数据
int flag = 1 << 3; // 需要清除第 4 个低位
int result = value & (~flag);// 使用这种方式运算进行位清除
赋值运算符
基本赋值运算符
- = 等号右边先执行,将直接结果赋值给左边的变量
扩展赋值运算符
- +=、-=、*=、/=、%=、&=、|=、^=、>>=、<<=、>>>=
- 以 += 为例。i += 3; 表示 i = i + 3;
- += 就是先+后=,也就是先求和,然后将求和的结果重新赋值。
- 对于扩展赋值运算符来说,有一个非常重要的运算规则需要注意:扩展赋值运算符不会改变运算结果的类型。(即使精度损失了,也不会改变运算结果类型。)
条件运算符
- Java 语言中的条件运算符由 ? 和 : 组成,也被称为三元运算符。它的语法格式为:布尔表达式 ? 表达式 1 : 表达式 2
- 当布尔表达式的值为 true 时,条件运算符的结果为表达式 1 的值,否则为表达式 2 的值。这种运算符常用于简化 if-else 语句的代码量。
- 下面是一个条件运算符的简单示例:
- int a = 5, b = 7;
- int max = (a > b) ? a : b;
- System.out.println("最大值为:" + max);
- 在上述代码中,首先定义了两个变量 a 和 b,然后使用条件运算符比较这两个变量的大小,取其中较大值作为变量 max 的值,最后输出结果。当 a > b 的结果为 false 时,条件运算符的结果为表达式 2,即 b 的值为变量 max 的值。当 a > b 的结果为 true 时,条件运算符的结果为表达式 1,即 a 的值为变量 max 的值。
- 总的来说,条件运算符在 Java 中的使用相对简单,能够减少代码重复和代码量,常用于简单的条件处理和表达式值的判断。
作业题
- 编写 Java 代码,输入一个半径值,计算圆的面积和周长,并输出结果。注意:圆的面积公式为 π*r*r,周长公式为 2 * π * r,其中 π 取 3.14
- 假设变量 a、b、c 分别为 6、9、10,请编写 Java 代码输出它们的最大值
- 假设变量 n 为整数,请编写 Java 代码判断它是不是一个偶数
- 编写 Java 代码,输入三个整数,分别判断第一个数是否大于 0,第二个数是否小于 10,第三个数是否是偶数。如果都满足条件,则输出“三个条件都满足”,否则输出“不满足所有条件”
- 编写 Java 代码,输入一个年份,判断它是否是闰年。若该年份能被 4 整除且不能被 100 整除,或者能被 400 整除,则该年份为闰年。输出结果为“该年是闰年”或“该年不是闰年”
控制语句
概述
控制语句:用于控制程序的执行流程,改变程序执行的次序。
- 分支语句 1. if 语句 2. switch 语句
- 循环语句 1. for 循环 2. while 循环 3. do while 循环
- 跳转语句 1. break 语句 2. continue 语句
分支语句 if
if 语句的第一种写法:
if(布尔表达式){ 分支语句; }
原理:如果布尔表达式 true,则执行分支语句。如果为 false,则不执行。
练一练:
- 编写一个程序,输入一个人的年龄 age,如果他的年龄大于等于 18 岁,则输出"你已经成年了",否则不输出任何东西。
- 编写一个程序,输入一个学生的分数 score(百分制),如果学生的分数大于等于 60,则输出"你已经及格了",否则不输出任何东西。
- 编写一个程序,输入一个学生的分数 score(百分制),如果学生的分数大于等于 60,则输出"你已经及格了",如果学生的分数小于 60,则输出“很抱歉,你不及格”。
if 语句的第二种写法:
if(布尔表达式){ 分支 1; }else{ 分支 2; }
原理:如果布尔表达式 true,则执行分支 1。如果为 false,则执行分支 2。
练一练:
- 编写一个程序,输入一个学生的分数 score(百分制),如果学生的分数大于等于 60,则输出"你已经及格了",如果学生的分数小于 60,则输出“很抱歉,你不及格”。
- 编写一个程序,输入一个数字 num,判断它是否为 7 的倍数。如果是,则输出"num 是 7 的倍数",否则输出"num 不是 7 的倍数"。
- 编写一个程序,输入一个数字 num,判断它是否同时为 3 的倍数和 5 的倍数。如果是,则输出"num 既是 3 的倍数又是 5 的倍数",否则输出"num 不同时是 3 的倍数和 5 的倍数"。
- 编写程序模拟用户登录,用户名和密码正确则登录成功,反之则登录失败。
if 语句的第三种写法:
if(布尔表达式){ 分支 1; }else if(布尔表达式){ 分支 2; }else if(布尔表达式){ 分支 3; }
原理:从上往下依次判断布尔表达式,只要遇到布尔表达式为 true,则执行对应的分支,整个 if 结束。如果都是 false,没有分支执行。
if 语句的第四种写法:
if(布尔表达式){ 分支 1; }else if(布尔表达式){ 分支 2; }else if(布尔表达式){ 分支 3; }else{ 分支 4; }
原理:从上往下依次判断布尔表达式,只要遇到布尔表达式为 true,则执行对应的分支,整个 if 结束。如果都是 false,没则执行最后的 else 分支。
练一练:
- 编写一个程序,输入一个数字 num,判断它是否为正数、负数或零,并输出对应的信息。例如,如果 num 是正数,则输出"num 是正数",如果 num 是负数,则输出"num 是负数",如果 num 等于 0,则输出"num 等于 0"。
- 编写一个程序,输入一个学生的分数 score(百分制),根据成绩的不同输出不同的评价。如果学生的分数大于等于 90 分,则输出"你的成绩是优秀";如果分数大于等于 80 分但小于 90 分,则输出"你的成绩是良好";如果分数大于等于 70 分但小于 80 分,则输出"你的成绩是中等";如果分数大于等于 60 分但小于 70 分,则输出"你的成绩是及格";否则输出"你的成绩不及格"。
- 编写一个程序,输入一个年份 year 和一个月份 month,判断这个月份有多少天。判断方法如下:
- 如果 month 为 1、3、5、7、8、10、12 中的一个,输出"month 有 31 天";
- 如果 month 为 4、6、9、11 中的一个,输出"month 有 30 天";
- 如果 month 为 2 并且 year 为闰年,输出"month 有 29 天";(如果一个年份能够被 4 整除但不能被 100 整除,或者能够被 400 整除,那么它就是闰年)
- 如果 month 为 2 并且 year 不是闰年,输出"month 有 28 天"。
if 语句的使用注意事项:
- 对于任何一个 if 语句来说,最多只能有一个分支执行。
- 分支中如果只有一条 Java 语句,大括号可以省略。
- 对于以上第 2 种和第 4 种,这两种写法是可以保证一定会有一个分支执行的。因为这两种写法都有 else 分支。
- 对于以上第 1 种和第 3 种,这两种写法可能会没有分支执行。
- 在 if 选择结构中还可以嵌套别的选择结构或循环结构。
练一练:
请输入性别以及当前气温: 如果是男: 气温低于 5 度(含 5 度),输出“请穿军大衣” 气温在 5~10 度(含 10 度),输出“请穿皮夹克” 气温高于 10 度,输出“你是硬汉子,请穿短袖” 如果是女: 气温低于 5 度(含 5 度),输出“请穿花棉袄” 气温在 5~20 度(含 20 度),输出“请穿羊绒衫” 气温高于 20 度,输出“请穿花裙子”
分支语句 switch
switch 语句完整格式:
switch 语句使用注意事项:
- switch 语句适用于判断固定值。if 语句适用于判断范围或区间时使用。switch 能做的 if 肯定能做,if 能完成的 switch 不一定能完成。
- JDK7 之前,switch 只支持 int 类型、枚举类型,在 JDK7 之后,增加了对字符串类型的支持。
- case 语句中的值必须是字面量,不能是变量。
- case 语句中的值必须和 switch 后面的值是同一类型,或者能够相互转换。
- case 可以合并。
- 在每个 case 分支中要加上 break 语句,以避免 case 穿透现象。
- 在 switch 语句中,一般都应该有一个 default 分支,用于处理一些特殊情况,以避免程序出错。(当然,default 语句不写,也不会编译报错。)
- switch 语句中的 default 分支可以放在 switch 块的任意位置,但是通常建议将 default 分支放在所有 case 分支的最后面。(可读性好)
switch 练一练:
- 编写一个程序,根据输入的月份,输出该月份所属的季节。
- 编写一个程序,根据输入的运算符符号,输出两个数的运算结果。例如输入符号为“+”,则输出两个数的和;输入符号为“-”,则输出两个数的差,以此类推。
- 编写一个程序,根据输入的图形名称,输出对应图形的边数。例如输入“三角形”,则输出“三角形有 3 条边”,以此类推。
- 编写一个程序,根据输入的成绩,输出对应的等级。例如输入成绩为 90~100,则输出“优秀”;输入成绩为 70~89,则输出“良好”,以此类推。
- 查询水果的价格,根据输入水果(fruit)的名字,输出对应的水果的价格,例如苹果 6 块/斤,香蕉 3 元/斤,榴莲 20 元/斤,西瓜 0.8 元/斤
Java12 中 switch 引入了新特性,代码变得更加简洁:
循环语句
循环语句:
当某代码片段需要频繁多次执行时,可以采用循环语句
循环语句 for
for 循环原理:
for 循环练一练:
- 输出 1~10
- 输出 1~100 中所有的偶数
- 输出 100,97,94,91...........1
- 计算 1~100 所有奇数的和。
- 计算 n 的阶乘。
for 循环嵌套:
for 循环嵌套 for 循环指的是在一个 for 循环的循环体中再嵌套另一个 for 循环。通过嵌套 for 循环,可以在外层循环的每次迭代中执行内层循环若干次。
例如,以下代码使用 for 循环嵌套打印九九乘法表:
java
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + " x " + i + " = " + i \* j + "\t");
}
System.out.println();
}
这段代码中,外层循环的循环变量为 i,它的取值范围是 1 到 9,每次迭代时执行内层循环。内层循环的循环变量为 j,它的取值范围是 1 到 i,这样可以确保每行只打印到当前行数的结果。在内层循环中,打印出 j 和 i 的积,用 tab 键隔开,使结果排列整齐。
for 循环练一练:
- 输出右侧图形
- 找出 1~100 的所有质数
- 找出 1~1000 的所有质数,输出时每 8 个换一行
- 输入一个正整数 n,计算 1-2+3-4+5-6+…-(n-1)+n 的和
- 输出 1 到 1000 之间既能被 5 整除又能被 3 整除的数,并且每行输出 5 个
- 求 100 到 999 之间的水仙花数。水仙花数的每个位上的数字的 3 次幂之和等于它本身(例如:1^3 + 5^3+3^3 = 153)
- 找 1~100 之间的质数,并输出两两相邻的质数差值等于 2 的质数对,例如(3,5),(5,7),(11,13),(17,19)等等
循环语句 while
while 循环:
- while 循环语法格式:
while(布尔表达式){ 循环体; }
练一练:
猜数字小游戏:程序生成 1~100 之间的一个随机数,要求用户猜这个数是多少,程序做出相应的提示,如果猜中了则输出恭喜信息,并记录猜的次数,如果猜错了可以提示用户再猜一次。使用 while 循环实现游戏的主体流程。
循环语句 do while
do while 循环:
- do while 循环语法格式:
do{ 循环体; }while(布尔表达式);
练一练:
- 求平均数:要求用户输入一组数字,用 -1 表示输入结束,使用 do-while 循环计算这些数字的平均数并输出。要使用一个计数器来记录输入的数字个数,遇到 -1 则终止输入并计算平均数。
跳转语句
跳转语句:
- break; 1. 出现在 switch 语句用来终止 switch 语句的执行。 2. 出现在循环中,用来终止循环的执行。 3. break; 用来终止离它最近的循环。 4. break 循环标记; 用来终止指定的循环。
- continue; 1. 终止当前本次循环,直接进入下一次循环继续执行。 2. continue; 终止当前本次循环,直接进入离它最近的循环继续。 3. continue 循环标记; 终止当前本次循环,直接进入指定的循环继续。
- break;与 return; 1. break;终止循环。 2. return;终止方法。
练一练:
- 请设计一个程序,不断的从键盘上接收一个正整数或者负整数,要求计算所有正整数的和,如果接收到 0,则程序退出。
- 请编写一个程序,打印 1~100 所有的奇数,但是跳过所有以数字 3 结尾的数字。
- 韩信点兵,三人一组余两人,五人一组余三人,七人一组余四人,请问最少需要多少士兵
方法
方法是什么,有什么用:
- 方法(Method)是一段可以被重复利用的代码片段。
- 一个方法一般都是一个独立的功能。
- 在 C 语言中叫做函数(Function)。
方法的定义和调用:
语法格式:
[修饰符列表] 返回值类型 方法名(形式参数列表){ 方法体; }
- 修饰符列表:可选项。目前固定写法 public static,后面课程中再做介绍。
- 返回值类型:用来指定方法返回值的数据类型(方法执行结束后的结果类型)。只要是 Java 合法的数据类型,都可以,例如:byte,short,int,long,float,double,boolean,char,String...。如果方法执行结束时没有返回任何数据,返回值类型也不能空着,需要写 void 关键字。
- 方法名:只要是合法的标识符即可。但最好见名知意。方法通常反应行为,所以方法名一般为动词。
- 形式参数列表:简称形参。用来接收数据。参数个数 0~N 个。如果有多个,使用逗号隔开。例如(int a, double b,long c)。每一个形式参数都可以看做局部变量。
- 每个方法都有方法体,方法体是一对大括号。在大括号中编写 Java 语句。
- 方法的调用:如果修饰符列表中 static 关键字,采用“类名.方法名(实际参数列表);”调用方法。 - 调用者和被调用者在同一个类中,“类名.”可以省略。 - 实际参数列表:简称实参,实参和形参要一一对应,个数对应,数据类型对应。
- 调用方法,如果方法执行结束后有返回值,可以采用变量接收该返回值。当然,也可以选择不接收。
方法执行时的内存变化:
- 方法只定义不调用是不会分配内存的。只是方法的字节码指令存储在元空间中。
- 方法调用时会给该方法在 JVM 的栈内存中分配空间,此时发生压栈动作。这个方法的空间被称为栈帧。
- 栈帧中主要包括:局部变量表,操作数栈等。
- 方法执行结束时,该栈帧弹栈,方法内存空间释放。
方法重载(overload):编译阶段的一种机制(静态多态)
- 什么情况下构成方法重载? 1. 在同一个类中 2. 方法名相同 3. 参数列表不同 - 类型不同算不同 - 顺序不同算不同 - 个数不同算不同
- 什么时候我们考虑使用方法重载? - 在同一个类中,如果功能相似,建议使用方法重载。
- 方法重载好处? - 简化代码调用。 - 更易维护。 - 代码美观。
递归:
- 什么是方法的递归调用?
- 递归时,内存是如何变化的?
- 递归使用注意事项?
- 递归必须要有结束条件。
- 递归和循环都能完成的话,优先选择循环。(递归更耗费内存。)
- 递归有结束条件,就一定不会栈内存溢出吗?
- 实际开发中,使用递归时,发生栈内存溢出,你该怎么办?
练一练:
- 使用递归计算 n 的阶乘。
- 假如有一对兔子,从出生后第 3 个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,请问第 n 个月后的兔子有多少对
package 和 import
package 包机制:
- 包机制作用:便于代码管理。
- 怎么定义包:在 java 源码第一行编写 package 语句。注意:package 语句只能出现在 java 代码第一行。
- 包名命名规范中要求是全部小写。
- 包名命名规范:公司域名倒序 + 项目名 + 模块名 + 功能名。例如:
- com.powernode.oa.empgt.service
- 如果带包编译:
- javac -d 编译后的存放目录 java 源文件路径
- 有了包机制后,完整类名是包含包名的,例如类名是:com.powernode.javase.chapter02.PackageTest
import:
- import 语句用来引入其他类。
- A 类中使用 B 类,A 类和 B 类不在同一个包下时,就需要在 A 类中使用 import 引入 B 类。
- java.lang 包下的不需要手动引入。
- import 语句只能出现在 package 语句之下,class 定义之前。
- import 语句可以编写多个。
- import 语句可以模糊导入:java.util.*;
- import 静态导入:import static java.lang.System.*;
IntelliJ IDEA 工具的使用
IDEA 工具的使用:
- IDEA 工具的安装。
- 如何新建空工程。
- 如何设置 JDK 以及编译器版本。
- 如何新建模块。
- 如何新建包,新建类。
- 如何运行 Java 程序。
- 如何设置字体大小。
常用的 IDEA 快捷操作
- alt+insert(新建/新增任何东西)
- 退出任何窗口 ESC
- 编写源码的窗口最大化 ctrl+shift+F12
- psvm 生成 main 方法
- 快速生成输出语句 sout
- IDEA 会自动保存,自动编译
- 打开 Project 窗口 alt+1
- 查找某个类:敲两次 shift,选择 classes,输入类名
- 切换选项卡:alt + 左右方向键
- 自动生成变量.var
- 删除一行 ctrl+y
- 复制一行 ctrl+d
- 在一个类当中查找方法 ctrl+F12
- 生成 for 循环:fori
- 自动生成 if 语句.if
常用的 IDEA 快捷操作
- 单行注释:ctrl + /
- 多行注释:ctrl + shift + /
- 查看源码:按 ctrl 别松手,鼠标移动到对应的类名下方,出现下划线,点击过去,可以查看类源码。
- 多行编辑:按 alt 别松手,鼠标拖动多行,完成多行编辑。
- 怎么快速生成创建对象语句:类名.new.var
- 怎么快速生成 if 语句:布尔类型值.if
- 怎么快速生成 setter 和 getter 方法:alt + insert,然后选择 setter and getter 生成。
- 怎么快速生成构造方法:alt + insert,然后选择 Constructor。
- 在 IDEA 当中如何自动纠错:将光标移动到错误的位置,按 atl + enter。会有提示,根据提示进行纠错。
- 移动代码到上一行:alt + shift + 上/下方向
- 怎么快速重写方法?alt + insert,选择 Override....
- 怎么快速重写方法?ctrl + o
- 快速向下转型,并同时生成变量名:变量名.castvar
- 快速查看方法的参数:ctrl + p
- 返回上一步:ctrl + alt + 左方向键。 下一步:ctrl + alt + 右方向键。
- 代码格式化:ctrl + alt + L。
- 查看继承结构:ctrl + H
- 自动代码包裹:ctrl + alt + t
练习题
猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又吃了一个,第二天早上又将剩下的桃子吃了一半,又多吃了一个,以后每天早上都是吃了前一天剩下的一半零一个,到第 10 天早上再吃的时候,发现只剩下一个桃子了,问一共多少个桃子。
100 个和尚吃了 100 个馒头,100 和尚有大和尚和小和尚,一个大和尚能吃 3 馒头,三个小和尚吃 1 个馒头,问大和尚和小和尚有多少个?
已知一只公鸡 5 块钱,母鸡 3 块钱,小鸡 1 块钱 3 只,问 100 元买 100 只鸡有哪些方案?
提示: 如果拿 100 元买公鸡,最多买 20 个。 如果拿 100 元买母鸡,最多买 33 个。 如果拿 100 元买小鸡,最多买 300 只。