Java 基础 二

343 阅读13分钟

第二章 Java 基础语法

关键字和保留字

关键字

定义: 被Java语言赋予了特殊含义,用做专门用途的字符串(单词)

特点: 关键字中所有字母都为小写

用于定义数据类型的关键字
  • class、interface、enum、byte
  • short、int、long、float、double
  • char、boolean、void
用于定义流程控制的关键字
  • if、else、swtich、case、default
  • while、do、for、break、continue、return
用于定义访问权限修饰符的关键字
  • private、protected、public

保留字

现有Java版本尚未使用,后续版本可能会作为关键字使用

  • goto
  • const

标识符

Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符

技巧: 凡是自己可以起名字的地方都叫标识符

定义合法标识符的规则:

  • 由26个英文字母大小写,0-9,_或$组成
  • 不能以数字开头
  • 不能使用关键字和保留字,但可以包含它们
  • 严格区分大小写,长度无限制
  • 不能包含空格

Java 中的标识符命名规范

见名知意,Java 采用unicode字符集,因此标识符可以使用汉字声明,但不建议使用

  • 包名: 多个单词组成时所有字母小写: xxxyyyzzz
  • 类名、接口名: 多个单词组成时,所有单词的首字母大写: XxxYyyyZzz
  • 变量名、方法名: 多单词组成时,除去第一个单词外,其余单词首字母大写: xxxYyyZzz
  • 常量名: 所有字母都大写,多单词时,每个单词用下划线连接: XXX_YYY_ZZZ

变量(重点)

  • 内存中的一个存储区域
  • 该去域的数据可以在同一类型范围内不断变化
  • 变量是程序中最基本的存储单元;包含 变量类型、变量名和存储的值

变量的作用

  • 用于在内存中保存数据

变量使用中的注意事项

  • Java 中每个变量必须先声明后定义
  • 使用变量名来访问这块区域的数据
  • 变量的作用域: 其所在的一对 "{...}"内
  • 变量只有在其作用与内才有效
  • 同一个作用域内不能定义重名的变量

变量的使用

  • Java定义变量的格式: 数据类型 变量名 = 变量值

  • 说明

    • 变量必须先声明后使用
    • 变量都定义在其作用域内,在作用域内,它是有效的,反之无效
    • 同一个作用域内,不能声明两个同名的变量(逆向思维,反证法)

基本数据类型(8种)

数值型

  • 整数类型

    • Java各整数类型有固定的表述范围和字段长度,不受具体OS的影响,以保证java程序的可移植性
    • java的整型常量默认为int型,声明long型常量后需加"l"/"L"
    • java程序中,变量通常声明为int型,除非不足以表示较大的数,才使用long型
    1. byte 1字节=8bit -128 ~ 127 === 2^8
    byte b1 = 12;
    byte b2 = -128;
    // byte b3 = 128; error 编译不通过
    
    1. short 2字节 -2^15 ~ 2^15 - 1 === 2^16
    short s1 = 123
    
    1. int 4字节 -2^31 ~ 2^31 - 1 (约21亿) === 2^32
    int i1 = 1234
    
    1. long 8字节 -2^63 ~ 2^63 - 1 === 2^64
    // 声明long类型变量,必须以"l"/"L"结尾
    long l1 = 852096374L
    
  • 浮点型

    • 浮点型,表示带小数点的数值
    • float表示数值的范围比long还要大
    • 定义float类型变量时,变量要以"f"/"F"结尾
    • Java的浮点型常量默认为double
    1. float: 单精度,尾数可以精确到7位有效数字,多数情况下很难满足需求
    // E === 10
    // 4字节,表数范围 -3.403E38 ~ 3.403E38
    float f1 = 12.3F;
    // float f2 = 123.4; // error 
    
    1. double: 双精度,精度是float的两倍;通常采用此类型
    // 8字节,-1.798E308 ~ 1.798E308
    double d1 = 85.0;
    

字符型 char (1字符=2字节)

  • 定义char型变量,通常使用一对单引号(''),也可以写ASCII码,不能使用双引号("")

  • 单引号中只能写一个字符,字符串中可以写多个字符

  • 表示方式:

    • 声明一个字符
    • 转义字符
    • Unicode 值表示(很少)
  • 转义字符:

    • \b: 退格符
    • \n: 换行符
    • \r: 回车符
    • \t: 制表符
    • \": 双引号
    • \': 单引号
    • \\: 反斜线
char c1 = 'a';
char c11 = 97; // 'a'
c1 = 'A';
// c1 = 'ab'; // error
char c2 = '中';

// 转义字符
char c3 = '\n'; // 换行符
System.out.print("hello" + c3);
System.out.println("world");
// hello
// world

char c4 = '\t'; // 制表符 tab 键
System.out.print("hello" + c4);
System.out.print("world");
// hello    world

// Unicode值
char c5 = '\u0043';
System.out.print(c5)
// c

布尔型 boolean

  • 只能取两个值之一: true / false
  • 常用于条件判断、循环结构中使用
boolean bb1 = true;
System.out.println(bb1);
// true
boolean isMarried = true;
if (isMarried) {
    System.out.println("sorry,\n你不能参加\"单身\"派对!");
    // sorry,
    // 你不能参加"单身"派对!
}else {
    System.out.println("请来参加单身派对!");
}

基本数据类型间的转换

前提: 这里只讨论7种基本数据类型间的运算,不包含boolean类型

自动类型转换(提升)
  • 同种数据类型中: 小类型 和 大类型 作运算时,结果自动提升为 大类型
  • byte、char、short -> int -> long -> float -> double
    • 特殊: 当 byte、short、char 三者之间作运算时,结果为int型
byte b1 = 2;
int i1 = 129;
// byte b2 = i1 + b1; error 编译不通过
int i2 = i1 + b1;
long l1 = i1 + b1;
float f1 = i1 + b1;
System.out.println(i2); // 131
System.out.println(f1); // 131.0
  • char类型与数据类型作运算,最小结果类型为int类型
char c1 = 'a' // 97
int i3 = 10;
int i4 = c1 + i3;
System.out.println(i4); // 107

short s1 = 10;
// char c2 = c1 + s1; // error 编译不通过
byte b1 = 10;
short s2 = b1 + s1; // error 编译不通过
byte b2 = 10;
byte b3 = b1 + b2; // error 编译不通过
int i5 = b1 + b2; // 只能通过int型来接收
System.out.println(i5); // 20
强制类型转换

强制类型转换: 自动类型提升的逆运算(大类型转为小类型)

  • 强转符: "(数据类型)", 数据类型 变量 = (数据类型)变量;
  • 注意,强制类型转换,可能导致精度损失
double d1 = 12.8;
int i1 = (int)d1; // 截断操作,损失精度
System.out.println(i1); // 12

long l1 = 123L;
short s1 = (short)l1; // 截断操作,没有精度损失
实际编码中的数据转换
  • long: 定义变量时,数据值没有超过int型时可以不加"l"/"L"
long l1 = 12345; // 默认 12345 为int型,可以转为long型
System.out.print(l1) // 12345
long l2 = 123456789134568; // error, 数据值超过int范围
  • float: 定义变量时一定要加"f"/"F"
float f1 = 12.3; // error,默认 12.3 为double型,不能转化为 float型
float f2 = 1 + 12.3; // 12.3默认为double型
  • byte: Java中的整型数据默认为int型
byte b1 = 12;
byte b2 = b1 + 1; // error, 整数 1 默认为int型,故b2的数据类型应该为 int型
int b2 = b1 + 1;
  • 总结: 整型常量,默认为int型;浮点型常量,默认为double型

基本数据类型与String(class)间转换

String: 字符串类型
  • String不是基本数据类型,属于引用数据类型

  • 声明String类型的变量时,必须使用一对双引号: ""

  • 使用方式与基本数据类型一致;如 String s1 = "ads";

  • 一个字符串可以串接另一个字符串,也可以直接串接其它类型的数据

    String s1 = "ads";
    s1 = s1 + '123';
    int n = 100;
    s1 = s1 + n
    String s2 = "1";
    String s3 = "";
    
  • String可以和8中基本数据类型变量作运算,且运算只能是连接运算: "+"(连接符)

  • String类型与其它类型的运算结果仍然是String类型

    int number = 1001;
    String numberStr = "学号: ";
    String info = numberStr + numner;
    System.out.print(info);
    // 学号: 1001
    
    boolean b1 = true;
    String info1 = info + b1;
    System.out.print(info1);
    // 学号: 1001true
    
练习
// 1.
char c = 'a';
int num = 10;
String str = 'hello';
System.out.print(c + num + str); // 107hello
System.out.print(c + str + num); // ahello10
System.out.print(c + (num + str)); // a10hello
System.out.print((c + num) + str); // 107hello
System.out.print(str + num + c); // hello10a
// 2.
System.out.println("*   *"); // *   *
System.out.println('*' + '\t' + '*'); // 93
System.out.println('*' + "\t" + '*'); // *  *
System.out.println('*' + '\t' + "*"); // 51*
System.out.println('*' + ('\t' + "*")); // *    *
// 3.
String str1 = 4; // error
String str1 = 3 + ""; // success
String str2 = 3.5F + ""; // "3.5"
System.out.println(3 + 4 + "Hello!"); // 7Hello!
System.out.println("Hello!" + 3 + 4); // Hello!34
System.out.println('a' + 1 + "Hello!"); // 98Hello!
System.out.println("Hello!" + 'a' + 1); // Hello!a1
// 4. 变量提升
short s1 = 5;
s1 = s1 + 2; // error
int s2 = s1 + 2; // success
byte b = 3;
b = b + 4; // error
b = (byte)(b + 4); // success
char c1 = 'a';
int i1 = 5;
float d = 3.14F;
double result = c1 + i1 + d; // success
byte b = 5;
short s = 3;
short t = s + b; // error
int t = s + b; // success

进制与进制间的转换(了解)

关于进制
  • 所有数字在计算机底层都以二进制形式存在

  • 对于整数,有四种表示方式

    • 二进制(binary): 0-1; 满二进一,以0b或0B开头
    • 十进制(decimal): 0-9; 满十进一
    • 八进制(octal): 0-7; 满八进一,以数字0开头表示
    • 十六进制(hex): 0-9及A-F; 满十六进一,以0x或0X开头表示(此处A-F不区分大小写)
int num1 = 0B110; // 6
int num2 = 100; // 100
int num3 = 0127; // 87
int num4 = 0X110A; // 4362
进制转换

每个进制的最高位称为符号位,0:正数,1:负数

正数中二进制到十进制的转换

int i = 0B1110;
// 0*2^0 + 1*2^1 + 1*2^2 + 1*2^3 = 14

十进制转化为二进制: 商除二,取余的逆

二进制转八进制: 从低向高,每三个二进制位代表一个八进制位

二进制转十六进制: 从低向高,每四个二进制位代表一个十六进制位

二进制
  • 二进制的整数有如下三种形式:

    • 原码: 直接将一个数值转换为二进制
    • 负数的反码: 对原码按位取反,只是最高位(符号位)确定为1
    • 负数的补码: 其反码加1
  • 计算机以二进制补码的形式保存所有的整数

    • 正数的原码、反码、补码都相同
    • 负数的补码是其反码加1

负数中二进制到十进制的转换

1 0 0 0 1 1 1 0 // -14的原码

// 除去符号位外,各个位取反
1 1 1 1 0 0 0 1 // -14的反码

// 反码 +1
1 1 1 1 0 0 1 0 // -14的补码
// 计算机底层都以补码的形式来存储数据!

// 练习
1 0 1 1 1 0 1 1 // 补码
// 补码 -1
1 0 1 1 1 0 1 0 // 反码
// 除符号位,反码取反
1 1 0 0 0 1 0 1 // 原码
1*2^0 + 1*2^2 + 1*2^6 = -69

// 
0 1 1 1 1 1 1 1 // +127
1 1 1 1 1 1 1 1 // -127原码
1 0 0 0 0 0 0 1 // -127补码
1 0 0 0 0 0 0 0 // -128补码

总结(重点)

标识符的命名规则
  • 以字母a-Z(区分大小写)、0-9、_和$表示
  • 不能以数字开头
  • 不能包含空格
  • 不能使用关键字保留字,但是可以包含关键字保留字
标识符的命名规范(见名知意)
  • 包: xxxyyyzzz
  • 类名、接口名: XxxYyyZzz
  • 变量名、方法名: xxxYyyZzz
  • 常量: XXX_YYY_ZZZ
Java 变量的数据类型的划分,并指出Java的8中基本数据类型,及各自所占空间大小
  • Java 变量的数据类型分为
  1. 基本数据类型

    • 数值型

      1. 整数类型 byte、short、int、long
      2. 浮点类型 float、bouble
    • 字符型 char

    • 布尔型 boolean

  2. 引用数据类型

    • 接口
    • 数组
  • Java 中的8中基本数据类型
  1. byte: 1字节=8位 2^8, -128 ~ 127
  2. short: 2字节=16位 2^16, -2^15 ~ 2^15
  3. int: 4字节=32位 2^32, -2^31 ~ 2^31
  4. long: 8字节=64位 2^64, -2^63 ~ 2^63
  5. float: 4字节
  6. double: 8字节
  7. char: 1字符=2字节
  8. boolean:true/false
基本类型间自动类型提升的运算规则
  • byte、short、char -> int -> long -> float -> double
  • String与8种基本数据类型变量作连接运算"+"都为String类型
基本数据类型之间强制类型转换的使用规则和可能出现的问题
  • 容量大 -> 容量小
  • 变量类型 变量名 = (变量类型)变量值;
  • 可能出现精度丢失
进制

二进制数据的存储方式: 所有数值,不管正负,底层都是以补码的方式存储

  • 正数: 原码、反码、补码 三码合一
  • 负数: 补码 = 反码 +1

运算符

算数运算符

  • + 正号/加/字符串连接

  • - 负号/减

  • * 乘

  • / 除

    int num1 = 12;
    int num2 = 5;
    int result1 = num1 / num2; // 2
    int result2 = num1 / num2 * num2; // 10
    
    double result3 = num1 / num2; // 2.0
    double result4 = num1 / (num2 + 0.0); // 2.4
    double result5 = (double)num1 / num2; // 2.4
    
  • % 取余,余数的符号与被除数的符号相同

    int m1 = 12;
    int n1 = 5;
    int res1 = m1 % n1; // 2
    // 余数的符号与被除数的符号相同
    int m2 = -12;
    int n2 = 5;
    int res2 = m2 % n2; // -2
    int m3 = 12;
    int n3 = -5;
    int res3 = m3 % n3; // 2
    int m4 = -12;
    int n4 = -5;
    int res4 = m4 % n4; // -2
    
  • ++ 自增1

    1. 前自增: 先自增一,后运算
    int a1 = 10;
    int b1 = ++a1;
    System.out.print("a1= " + a1 + ", b1= " + b1);
    // a1 = 11, b1 = 11
    
    1. 后自增: 先运算,后自增一
    int a2 = 10;
    int b2 = a2++;
    System.out.print("a2= " + a2 + ", b2= " + b2);
    // a2 = 11, b2 = 10
    
    short a3 = 10;
    // a3 = a3 + 1; error 编译失败
    // a3 = (short)(a3 + 1); // success
    a3++; // 自增1,不会改变本身变量的数据类型,效率更高
    
    // 问题
    byte bb1 = 127;
    bb1++;
    System.out.pringln("bb1 = " + bb1);
    // bb1 = -128
    // 1 0 0 0 0 0 0 0
    
  • -- 自减1,与自增1类似

    int a4 = 10;
    int b4 = a4--;
    System.out.println("a4 = " + a4 + ", b4 = " + b4);
    // a4 = 9, b4 = 10
    
    // 去除一个三位数的个、十、百位的值
    int num = 187;
    int bai = num / 100;
    int shi = num % 100 / 10; // num / 10 % 10;
    int ge = num % 10;
    

赋值运算符: =

  • 当"="两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理
  • 支持连续赋值
  • 扩展运算符: +=、-=、*=、/=、%=
  • 运算的结果不会改变变量本身的数据类型
int i1 = 10;
int j1 = 10;
int i2, j2;
i2 = j2 = 10; // 连续赋值
int i3 = 10, j3 = 20;

int num1 = 10;
num1 += 2; // num1 = num1 + 2;
System.out.println(num1); // 12
int num2 = 12;
num2 % = 5;
System.out.println(num2); // 2

short s1 = 10;
s1 += 2; // 不会改变变量本身的数据类型,效率更高
System.out.println(s1); // 12
// 开发中,如果希望变量实现加2的操作,有几种方法?
int num = 2;
num = num + 2; // 1.
num += 2; // 2.效率更高

// 练习1
int i = 1;
i *= 0.1;
System.out.println(i); // 0
i++;
System.out.println(i); // 1

// 练习2
int m = 2;
int n = 3;
n *= m++;
System.out.println("m = " + m); // 3
System.out.println("n = " + n); // 6

// 练习3
int n = 10;
n += (n++) + (++n);
System.out.println(n); // 32

比较运算符

比较运算符的结果都是 boolean 类型

  • == 相等于 4==3 false
  • != 不等于 4!=3 true
  • < 小于 4<3 false
  • /> 大于 4>3 true
  • <= 小于等于 4<=3 false
  • >= 大于等于 4>=3 true
  • instanceof 检查是否是类的对象 "Hello!" instanceof String true

逻辑运算符

操作的都是布尔类型的变量

  • & 逻辑与
  • | 逻辑或
  • ! 逻辑非
  • && 短路与
  • || 短路或
  • ^ 逻辑异或 a^b 相同为false,异同为true
& 与 && 的异同(开发中推荐使用 && )
  • 相同点:

    1. & 与 && 的运算结果相同
    2. 当符号左边为 true时,两者都会执行符号右边的运算
  • 异同点:

    1. 当符号左边是false时,& 继续执行符号右边的运算,&& 不再执行符号右边的运算
int x = 1;
int y = 1;
if(x++==2 & ++y==2) {
    x = 7
}
System.out.println("x= " + x + ", y= " + y);
// x=2, y=2

int i = 1, j = 1;
if(i++==2 && ++j==2) { i = 7 }
System.out.println("i= " + i + ", j= " + j);
// i = 2, j = 1
| 与 || 的异同(开发中推荐使用 || ),与上边类似

位运算符(了解)

位运算是直接对整数的二进制进行的运算

  • << 左移(*2^n) 3<<2=12 -> 3*2*2=12
    • 左移,在一定范围内 res*2^n, n是左移的位数
    • 规则: 空位补0,被移除的高位直接丢弃
  • >> 右移(/2^n) 3>>1=1 -> 3/2=1
    • 右移,在一定范围内 res/2^n, n是右移的位数
    • 规则: 正数,右移后空缺位补0;负数,右移后空缺位补1
  • >>> 无符号右移(集合,求hash值) 3>>>1=1 -> 3/2=1
    • 规则: 右移,空缺位直接补0
  • & 与运算 6&3=2
  • | 或运算 6|3=7
  • ^ 异或运算 6^3=5
  • ~ 取反运算 ~6=-7
// 面试题: 最高效方式计算 2*8
2 << 3; // 2*2*2*2
8 << 1; // 8*2

// 练习: 交换两个变量的值
int i = 12;
int j = 22;
// 1. 通用性
int temp = i;
i = j;
j = temp;
// 2. 可能超出存储范围,只能操作数值型
num1 = num1 + num2;
num2 = num1 - num2;
num1 = num1 - num2
// 3. k = m ^ n; m = k ^ n = (m ^ n) ^ n (规则)
// 有局限性,只适用于数值类型
i = i ^ j;
j = i ^ j;
i = i ^ j;

三元运算符

格式: 数据类型 变量名 = (条件表达式) ? 表达式1 : 表达式2;

  • 条件表达式为 true,执行表达式1, 反之,执行表达式2
  • 表达式1和表达式2为同种类型
  • 三元运算符可以嵌套使用
  • 三元运算符与 if-else 的异同:
  1. 三元运算符可看作 if-else 的简化(三元运算符的效率高)
  2. 三元运算符要求必须返回一个结果
  3. if 中的代码块可有多个语句
  4. 凡是可以使用三元运算符的地方,都可以改写为 if-else,反之不成立
int num = 10;
// 必须接收返回的结果
num = (num > 10) ? 20 : 12;
System.out.println("num = " + num); // 12

// 两个表达式的类型要统一
// (m > n) ? 2 : "n大"; error,找不到合适的类型去接收返回值

int m = 10;
int n = 10;
// 三元运算符的嵌套
String maxStr = (m > n) ? "m" : ((m == n) ? "m == n" : "n");
System.out.println(maxStr);

程序流程控制(重点)

顺序结构

程序从上到下顺序执行

分支结构

根据条件,选择性的执行某段代码,有 if-else 和 switch-case 两种分支语句

if ... else if ... else
  • if 或 else if 语句后,只能使用布尔表达式或布尔值作为分支条件来进行分支控制
  • if else if 可以嵌套
  1. if
  2. if - else 二选一
  3. if - else if ... - else 多选一
  • 从键盘获取不同类型的变量: 使用Scanner类,具体实现步骤如下:

    1. 导包: import java.util.Scanner;
    2. Scanner实例化: Scanner scan = new Scanner(System.in);
    3. 调用Scanner类中的方法来获取指定类型的变量
    // 从键盘获取不同类型的变量: 使用Scanner类
    // 导包
    import java.util.Scanner;
    class ScannerTest {
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in); // 实例化Scanner类
            // nextInt、nextBoolean、nextByte、nextDouble、next ...
            int num = scan.nextInt(); // 获取键盘输入的数据
            System.out.println("num = " + num);
        }
    }
    
switch ... case ... default

结构: switch (expression) { case condition(常量): ... break; ... default: ...;}

  • switch 语句后表达式的数据类型只能是 byte、short、char、int、枚举类型(5.0)、String类型(7.0),这六种类型之一
  • case 语句后的条件只能是常量,代码块中的 break, 被省略时,会进入陷阱
  • default: 相当于 else 语句(备胎),且default结构是可选的、位置也是灵活的(默认位置写在最后)
  • 如果switch - case 中多个case条件的执行语句相同则可以合并

switch特性:

  1. 相同的执行语句,case可以合并
  2. 灵活使用 break
// 'a' == 97; 'A' == 65
char c1 = 'B';
switch (c1) {
    case 'A': 
        System.out.println("very good");
        break;
    case 'B':
        System.out.println("good");
        break;
    case 'C':
        System.out.println("middle");
        break;
    case 'D':
        System.out.println("tail");
        break;
    default:
        System.out.println("fail");
}
// >= 60 及格,< 60 不及格
int score = 78;
switch(score / 60) {
    case 0: 
        System.out.println("false");
        break;
    case 1:
        System.out.println("true");
        break;
    default:
        System.out.println("return");
}
// 算出当前日期是当年的第几天
// 利用 switch 的特性break
switch (month) {
    case 12:
        sumDays += 30;
    case 11:
        sumDays += 31;
    // ...
    case 3:
        sumDays += 28;
    case 2:
        sumDays += 31;
    case 1:
        sumDays += day;
}
System.out.println("days" + sumDays);
if-else与switch-case总结:
  1. 凡是可以使用switch-case的结构,都可以转换为if-else;反之,不成立
  2. 选择分支结构时,发现既可以使用switch-case又可以使用if-else时,优先使用switch-case,原因是switch-case执行效率稍高
  3. 三元运算符和switch-case语句都可以转化为if-else语句,反之,不一定成立
  4. 优先使用三元运算符和switch-case语句,执行效率较高

循环结构

循环结构四要素:
  1. 初始化条件
  2. 循环条件 -- boolean类型
  3. 循环体(有限性)
  4. 迭代条件
  • 说明: 通常情况下,循环结束都是因为2中的循环条件返回了false

根据循环条件,重复性的执行某段代码,有while、do...while、for 三种循环语句

  • while循环和for循环可以相互转化,只是初始化条件的作用域不同
  • 开发中多使用for和while循环,do-while较少
while

结构: while (布尔表达式/布尔值) { ... }

  • 先判断,后执行
  • 执行过程: 1 - 2 - 3 - 4 - 2 - 3 - 4 ...
  • 经常用于初始化条件复杂的情况
int i1 = 0;
while (i1 < 10) {
    ++i1;
}
System.out.println("i1 = " + i1); // 10
do while

结构: do {...} while (布尔表达式/布尔值)

  • 先执行,后判断
  • 执行过程: 1 - 3 - 4 - 2 - 3 - 4 - 2 ...
int i2 =10;
do {
    --i2;
} while (i2 >= 0); // 必须加分号 ";"
System.out.println("i2 = " + i2); // -1
for

结构: for (init_state; 逻辑表达式(boolean); iteration_statement) { statement ...}

  • 大部分情况下,for 循环可以替代 while、do..while循环
  • 初始化变量可以有多个,但数据类型必须相同,因为只能有一个声明语句,因此这些变量必须是相同的数据类型
  • 执行过程: 1 - 2 - 3 - 4 - 2 - 3 - 4 ...
  • 经常用于数组、字符串等
for (int = 0; i < 10; ++i) {
    System.out.println("i = " + i); // 0 1 ... 9
}
// 求两个数的最大公约数,和最小公倍数
import java.util.Scanner;
class ForTest{
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		System.out.println("first value m");
		int m = scan.nextInt();
		System.out.println("second value n");
		int n = scan.nextInt();
		int min = (m <= n) ? m : n;
		// 最大公约数
		for (int i = min; i >= 1; --i) {
			if (m % i == 0 && n % i == 0) {
				System.out.println("max zui da gong yue shu " + i);
				break;
			}
		}
		int max = (m >= n) ? m : n;
		int maxValue = m * n;
		// 最小公倍数
		for (int i = max; i <= maxValue; ++i) {
			if (i % m == 0 && i % n == 0) {
				System.out.println("min zui xiao gong bei shu " + i);
				break;
			}
		}
	}
}
// 输出100内的所有质数
// 质数: 从2开始到n-1结束,都不能被这个数n整除;最小的质数是 2
// 获取当前时间的毫秒数 System.currentTimeMillis() 距离1970:01:01:00:00的毫秒数
class ForPrime {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        for(int i = 2; i < 100; ++i) {
            boolean isFlag = true;
            for(int j = 2; j <= Math.sqrt(i); ++j) {
                if(i % j == 0) {
                    isFlag = false;
                    break;
                }
            }
            if(isFlag) {
                System.out.println("is prime " + i);
            }
            isFlag = true;
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime) + "ms");
    }
}
总结:
  1. 不在循环条件部分限制次数的结构(无限循环): for(;;) === while(true)
  2. 结束循环的方式: 循环条件部分返回 false 或 在循环体中执行 break,可以共同出现
控制循环结构

Java 为了提高程序的灵活性,提供了continuebreak来控制循环结构

  • 使用 break 完全结束一个循环

    1. break 可以结束其所在的循环
    2. break 还可以结束本循环的外层循环(当然,外层循环结束,本循环也会结束),结构: 标识符: break 标识符;
    // 可以终止 for、while、do while 等循环
    for(int i = 10; i > 0; --i) {
        if(i == 5) {
            System.out.println("i = " + i); // 5
            break;
        }
    }
    
    // 标识符:
    outer:
    for (int i = 0; i < 10; ++i) {
        for (int j = 0; j < 10; ++j) {
            if (i == 0 && j == 1) {
                System.out.println("i = " + i + ", j = " + j);
                break outer; // 结束外层循环
            }
        }
    }
    
  • 使用 continue 结束本次循环,并进入下一次循环

    1. continue 的作用是略过当次循环中后面的语句,重新开始新的循环
    2. 如果将 continue 语句放在单次循环结构的最后一行是没有意义的,因为它没有忽略任何程序语句
    3. 与 break 类似,continue 也可以紧跟一个标签,用于直接结束标签所标识循环的当次循环,直接进入下一次循环;格式: 标签: continue 标签;
    // 标识符:
    outerContinue:
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (i < 3) {
                continue outerContinue;
            }
            System.out.println("i = " + i + ", j = " + j);
        }
    }
    // i = 3, j = 0
    // i = 3, j = 1
    // i = 3, j = 2
    

问答题

& 和 && 的异同

  • & 逻辑与

  • && 短路与(推荐使用)

  • 相同点:

    • 只用同为 true 时,结果才为 true
    • 左边为 true 时,右边的表达式才会执行
  • 异同点:

    • & 的左右两边的表达式都会执行
    • && 左边的表达式为true时,才会执行右边的表达式

定义三个变量,获取三个数中的较大值

int i1 = 20;
int i2 = 100;
int i3 = -12;
int max;
if(i1 > i2 && i1 > i3) {
	max = i1;
}else if(i2 > i1 && i2 > i3) {
	max = i2;
}else {
	max = i3;
}
System.out.println("max = " + max); // 100

两个变量值的交换

int i = 10;
int j = 12;
int temp;
temp = i;
i = j;
j = temp;
// 数值型,可以使用位运算符
// k = m ^ n; m = k ^ n = (m ^ n) ^ n;
int i4 = 10;
int i5 = 16;
i4 = i4 ^ i5;
i5 = i4 ^ i5;
i4 = i4 ^ i5;

求一个0-255范围内整数的十六进制,如输出60的十六进制表示

// 使用 Java 内部的方法
String str1 = Integer.toBinaryString(60); // 0011 1100
String str2 = Integer.toHexString(60); // 3c
// 手动实现
int i1 = 60;
int i2 = i1 & 15;
String j = (i2 > 9) ? (char)(i2 - 10 + 'A') + "" : i2 + "";
int temp = i1 >>> 4;
i2 = temp & 15;
String k = (i2 > 9) ? (char)(i2 - 10 + 'A') + "" : i2 + "";
System.out.println(k + "" + j);

获取一个两位数的随机数

// 公式:[a,b] -> (int)(Math.random() * (b - a + 1) + a)
int value = (int)(Math.random() * 90 + 10);
System.out.println(value)

判断是否相同: str.equals("是")

import java.util.Scanner;
class IfExper {
    Scanner scan = new Scanner(System.in);
    System.out.println("is / no");
    String isHandSome = scan.next();
    if(isHandSome.equals("is") {
        System.out.println("is");
    }
}

算法的好坏

  • 正确性
  • 可读性
  • 健壮性
  • 高效率与低存储:时间复杂度(更重要)、空间复杂度