程序流程控制
顺序结构
- 程序从上到下逐行地执行,中间没有任何判断和跳转。
分支结构
- 根据条件,选择性地执行某段代码。
- 有if...else和switch两种分支语句。
循环结构
- 根据循环条件,重复性的执行某段代码。
- 有while、do…while、for三种循环语句。
- 注:JDK1.5之后提供了foreach循环,方便的遍历集合、数组元素。
顺序结构
Java中定义成员变量时采用合法的向前引用。
//正确形式:
public class Test{
int num1 = 12;
int num2 = num1 + 2;
}
//错误形式:
public class Test{
int num2 = num1 + 2; //报错,没有声明num1,无法引用
int num1 = 12;
}
分支(选择)结构
If-else 语句
语法格式:
if 单选择结构:
if(true){ 执行代码块; }
if-else 双选择结构:
if(条件表达式){ 执行代码块; }else{ 执行代码块; }
if-else if-else 多选择结构:
if(条件表达式){ 执行代码块; }else if(条件表达式){ 执行代码块; }... else{ 执行代码块; }
switch 语句
语法格式:
switch 多选择结构:
switch(变量){ case 常量1: 语句1; break; case 常量2: 语句2; break; ... case 常量N; 语句N; break; default: 语句; break; }
switch语句有关规则:
- switch(表达式) 中表达式的返回值必须是下述几种类型之一:byte、short、char、int、枚举、String
- case子句中的值必须是常量,而且所有case子句中的值是不同的
- default子句是可以任选的,当没有匹配的case时,执行default子句
- break是必须写的,break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾,也就是从case匹配到的位置开始一直往下执行到结尾
switch和if语句的对比:
if和switch语句很像,不同场景下应该怎么选用?
- 如果判断的具体数值不多,而且符合byte、short、int、char、String这几种类型。虽然两个语句都可以使用,但建议使用switch语句,因为效率稍高。
- 其他情况:对区间判断,对结果为boolean类型判断,使用if。if的适用范围更广 ,当你不知道应该使用if还是switch时,都使用if就可以。编程中主要是使用if。
循环结构
- 循环语句功能
在某些条件满足的情况下,反复执行特定代码的功能
循环语句的四个组成部分
- 初始化部分(init statement)
- 循环条件部分(test exp)
- 循环体部分(body statement)
- 迭代部分(alter statement)
循环语句分类
- for 循环
- while 循环
- do/while 循环
for 循环语句
语法格式:
for(初始化表达式①;布尔值测试表达式②;迭代因子④){
语句或语句块/循环体③;
}
Java里能用到逗号运算符的地方屈指可数,其中一处就是for循环的控制表达式。在控制表达式的初始化和步进迭代控制部分,我们可以使用一系列逗号分隔的表达式,而那些表达式均会独立执行。
for(int i = 1,j = i + 10; i < 5; i++,j = i * 2){ System.out.println("i= " + i +"j= " + j); }
在for语句的初始化部分声明的变量,其作用域为整个for循环体,不能在循环外部使用该变量
for(int i = 1;i < 10;i++){ System.out.println(i + "、"); } //编译错误,无法访问在for循环中定义变量i //System.out.println(i);
while 循环语句
语法格式:
初始化语句;
while(布尔值测试表达式){
语句或语句块/循环体;
迭代因子;
}
do-while 循环语句
语法格式:
初始化语句;
do{
语句或语句块/循环体;
迭代因子;
}while(布尔值测试表达式);
无限循环
最简单的无限循环格式:while(true)、for(;;),无限循环存在的原因是并不知道循环多少次,需要根据某些条件,来控制循环。
嵌套循环
- 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for、while、do…while均可以作为外层循环和内层循环。
- 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会完全跳出内层循环,才可结束外层循环的当次循环,开始下一次的循环。
设外层循环次数为m次,内层循环为n次,则内层循环体实际上需要执行m*n=mn次。
for(int i = 0;i < 3;i++){//每一次循环都会执行大括号里面所有的代码 System.out.println("大循环---" + i); for(int j = 0;j < 2;j++){//大循环次数乘以小循环次数就是小循环的大括号里面执行的代码次数 System.out.println("大循环---" + i + "小循环---" + j); } } /*运行结果是? 大循环---0 大循环---0小循环---0 大循环---0小循环---1 大循环---1 大循环---1小循环---0 大循环---1小循环---1 大循环---2 大循环---2小循环---0 大循环---2小循环---1 */
注意:在写嵌套循环的时候,要尽量保证外层循环的次数小于内层循环的次数
//不建议这样写
for(int i = 0;i < 900;i++){
for(int j = 0;j < 20;j++){
……
}
}
//建议这样写
for(int j = 0;j < 20;j++){
for(int i = 0;i < 900;i++){
……
}
}
//在编写代码时,如果上面的for循环与下面的for循环可以达到同样的逻辑效果时,要尽量采用下面这种
九九乘法表
for(int i = 1;i <= 9;i++) { for(int j = 1;j <= i;j++) {//j是i的内部循环,每行数字是小于等于i的 System.out.print(j + " * " + i + " = " + (i * j) + "\t"); }//要符合乘法表的规律,输出时i与j的位置要互换,字符串拼接最后要加制表符排版 System.out.println();//每输出一行i换一行 }
1~100之间所有的质数(质数是一个大于1的自然数并且只能被1和本身整除)
//思路:例如1~7,先外部循环1到7,假设取到6 //再用6和内部循环1~6之间的数分别取模,看能整除的次数 //如果整除的次数只有2次,那可以判断是一个质数 int count = 0;//声明一个计数器用于记录输出质数的总个数 for(int i = 1;i <= 100;i++) {//遍历1~100之间的整数 int frequency = 0;//声明整除次数用于判断质数 for(int j = 1;j <= i;j++) {//遍历1~外部循环取得的数之间的整数 if(i % j == 0) {//判断是否能被整除 frequency++;//能,整除次数加1 } } if(frequency == 2) {//判断整数次数是否等于2 System.out.print(i + " ");//等于2,输出这个质数 count++;//每输出一个质数,计数器加1 } } System.out.println("\n" + "1~100之间的质数一共有" + count + "个");
特殊流程控制语句
break 语句
break语句用于终止某个语句块的执行
{…… break; …… }
- break终止当前所在的循环
continue 语句
continue语句用于跳过某个循环语句块的一次执行,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
for(int i = 0;i < 100;i++){ if(i % 10 == 0){ continue;//结束当前这次循环,直接进入下一次循环 } System.out.println(i); }
这里有空看一下高淇视频关于continue注意事项,忘记了!!!
continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环。
//控制嵌套循环跳转(打印101-150之间所有的质数) outer: for (int i = 101; i < 150; i++) { int count = 0; for (int j = 1; j <= i; j++) { if (i % j == 0){ count++; } } if(count != 2) { continue outer; } System.out.print(i + " "); }
return 语句
- return并非专门用于结束循环的,它的功能是结束一个方法。当一个方法执行到一个return语句时,这个方法将被结束。
与break和continue不同的是,return直接结束整个方法,不管这个return处于多少层循环之内。
for(int i = 0;i < 2;i++){ for(int j = 0;j < 2;j++){ if(j == 1){ //return;//不会有输出结果,整个方法被结束了 break;//终止当前循环,输出0,1 } } System.out.println(i); }
特殊流程控制语句说明
- break只能用于switch语句和循环语句中。
- continue只能用于循环语句中。
- 二者功能类似,但是continue是终止本次循环,break是终止本层循环。
- break、continue之后不能有其他语句,因为程序永远不会执行其后的语句。
数组
数组的定义
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。
数组的三个基本特点:
- 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 其元素必须是相同类型,不允许出现混合类型。
- 数组类型可以是任何数据类型,包括基本类型和引用类型。
一维数组的声明
type[] var;//推荐选择一种方式使用
type var[];
//例如:
int[] a1;
一维数组初始化
静态初始化:在定义数组的同时就为数组元素分配空间并赋值。
int[] a = {3,9,8};//声明了一个存放了3、9、8这三个数的数组 int a[] = new int[]{3,9,8};//同上
动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行。
int[] arr = new int[3];//声明一个能放3个int类型数据的数组 arr[0] = 3;//给数组元素赋值 arr[1] = 9;//给数组元素赋值 arr[2] = 8;//给数组元素赋值
数组的默认初始化:数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
int a2[] = new int[2];//默认值:0,0 boolean[] b = new boolean[2];//默认值:false,false String[] s = new String[2];//默认值:null,null
数组元素的引用
- 定义并运用运算符new为之分配空间后,才可以引用数组中的每个元素。
数组元素的引用方式:数组名[数组元素下标]
- 数组元素下标可以是整型常量或者整型表达式。例如:a[3]、b[i]、c[6*i]
数组元素下标从0开始,长度为n的数组合法下标取值范围:0 → n-1。
String[] strs = new String[]{"c","a","b"}; System.out.println(strs[1]);//输出的结果是?a
每个数组都有一个属性length指明它的长度,例如:a.length指明数组a的长度(元素个数)。数组一旦被初始化,其长度是不可改变的。
String[] strs = new String[]{"c","a","b"}; System.out.println(strs.length);//输出的结果是?3
多维数组
二维数组[] []:数组中的数组
动态初始化(格式1)
int[][] arr = new int[3][2]; /* 定义了名称为arr的二维数组 二维数组中有3个一维数组 每一个一维数组有2个元素 */
动态初始化(格式2)
int[][] arr = new int[3][]; /* 定义了名称为arr的二维数组 二维数组中有3个一维数组 每个一维数组都是默认初始化值null */ int[][] arr = new int[][3];//非法
静态初始化
int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}}; /* 定义了名称为arr的二维数组 二维数组中有3个一维数组 每一个一维数组中具体元素也都已初始化 第三个一个数组长度的表示方式:arr[2].length; */
- 注意特殊写法情况:int[] x,y[]; //x是一维数组,y是二维数组
- Java中多维数组不必都是规则矩阵形式
//获取arr数组中所有元素的和。 int[][] arr = new int[][] { {3,8,2}, {2,7}, {9,0,1,6} }; int sum = 0; for(int i = 0;i < arr.length;i++) { for(int j = 0;j < arr[i].length;j++) { sum += arr[i][j]; } } System.out.println(sum);
常见算法与问题
数组操作中,可以使用等于(=)赋值,注意:此时新数组只是指向原数组的存储空间,并没有重新申请新的空间。