我们知道程序是从上往下依次执行的,但有的时候我们必须改变程序的执行顺序,如到达某个条件才执行某段程序,这样我们必须对程序的执行流程加以控制;
if 被翻译为如果,如果布尔表达式成了(结果为真),则执行if语句中的程序,反之不执行;
if(条件表达式){ 执行的语句... }
例如:今天上班了吗?上了(真),奖励100块钱;
/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { boolean job = true; if(job){ System.out.println("奖励100块钱!"); } } }
else翻译过来是"其他",当if中的条件表达式不满足时,则执行else中的语句;
例如:今天下雨了吗?下了(真),打不了篮球了,没下(假)可以去打篮球了!
/** * @author lscl * @version 1.0 * @intro: */ public class Demo02 { public static void main(String[] args) { boolean raining = false; if(raining){ System.out.println("打不了篮球了!"); }else{ System.out.println("去打篮球吧!"); } } }
当输出结果可能有多个条件时,如果我们需要根据不同的结果来反馈不同的信息,就需要使用到if…else if…else语句了;
例如:数字1代表男,数字0代表女,其他数字提示输入错误!
/** * @author lscl * @version 1.0 * @intro: */ public class Demo03 { public static void main(String[] args) { int sex = 1; if (sex == 1) { System.out.println("你是男的啊!"); } else if (sex == 0) { System.out.println("你是女的啊!"); } else { System.out.println("???"); } } }
需求:指定学生的成绩,范围在[0-100],根据成绩判断等级;
[90-100]等级为“优秀”
[80-90)等级为“良好”
[70-80)等级为“中等”
[60-70)等级为“及格”
[0-60)等级为“不及格”
其它数字表示成绩不合法。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo04 { public static void main(String[] args) { int score = 88; if (score < 0 || score > 100) { System.out.println("对不起,您输入的成绩不合法!"); } else if (score >= 90 && score <= 100) { System.out.println("成绩等级:优秀"); } else if (score < 90 && score >= 80) { System.out.println("成绩等级:良好"); } else if (score < 80 && score >= 70) { System.out.println("成绩等级:中等"); } else if (score < 70 && score >= 60) { System.out.println("成绩等级:及格"); } else if (score < 60 && score >= 0) { System.out.println("成绩等级:不及格"); } } }
switch 语句和 if 语句一样,都属于选择语句(分支语句),不再赘述,我们直接来看一下一个比较完整的 switch 语句结构是怎样的,请看下图:
需求:根据数字判断是星期几;
/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { // 定义变量,判断是星期几 int weekday = 3; //switch语句实现选择 switch (weekday) { case 1: System.out.println("星期一"); break; case 2: System.out.println("星期二"); break; case 3: System.out.println("星期三"); break; case 4: System.out.println("星期四"); break; case 5: System.out.println("星期五"); break; case 6: System.out.println("星期六"); break; case 7: System.out.println("星期日"); break; default: System.out.println("输入有误!"); break; } } }
tips:switch语句中,表达式的数据类型,可以是byte,short,int,char,enum(枚举),JDK7后可以接收字符串。
在switch 语句当中 case 是可以进行合并的,例如以下代码:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo02 { public static void main(String[] args) { int season = 3; switch (season){ case 1: case 2: case 3: System.out.println("爆竹声中一岁除,春风送暖入屠苏"); break; case 4: case 5: case 6: System.out.println("接天莲叶无穷碧,映日荷花别样红"); break; case 7: case 8: case 9: System.out.println("塞下秋来风景异,衡阳雁去无留意"); break; case 10: case 11: case 12: System.out.println("窗含西岭千秋雪,门泊东吴万里船"); break; } } }
switch 语句当中当某个分支匹配成功,则开始执行此分支当中的 java 语句,当遇到当前分支中的“break;”语句,switch 语句就结束了,但是如果当前分支中没有“break;”语句,则会发生 case 穿透现象,也就是说下一个分支也不再进行匹配,直接进入下一个分支执行,直到遇到break为止。
示例:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo03 { public static void main(String[] args) { int i = 1; switch (i) { case 0: System.out.println("0"); break; case 1: System.out.println("1"); case 2: System.out.println("2"); default: System.out.println("default"); } } }
执行情况:
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,能否继续重复,取决于循环的终止条件。循环结构是在一定条件下反复执行某段程序的流程结构,被反复执行的程序被称为循环体。循环语句是由循环体及循环的终止条件两部分组成的。
Java中有三种主要的循环结构:
while是最基本的循环,它的结构为:
while(条件表达式) { // 循环内容 }
/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { while (true){ System.out.println("执行了循环体"); } } }
在上述代码中,由于条件表达式是一个定值,要么一直true,要么一直为false,为true则一直执行循环体,造成死循环;为false则不会执行一次循环体的代码;
那么使用 while 循环实现输出 1~5 应该怎么做呢?
我们尝试改进一下条件表达式中的条件:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo02 { public static void main(String[] args) { int i = 1; while (i <= 5) { System.out.println("执行了" + i + "次"); /* 执行完毕一次循环体i自增1 i的变化: 1,2,3,4,5 */ i++; } } }
我们前面尝试使用while循环输出1~5的值,其写法有很多种,大家可以参考:
public static void print1() { int i = 0; while (i < 5) { System.out.println("执行了" + (i + 1) + "次"); /** * i的变化值: 0,1,2,3,4 */ i++; } }
public static void print2() { int i = 0; while (i < 5) { /** * i的变化值: 0(不打印),1,2,3,4,5 */ System.out.println("执行了" + (++i) + "次"); } }
public static void print3() { int i = 1; while (i <= 5) { /** * i的变化值: 1,2,3,4,5,6(不打印) */ System.out.println("执行了" + (i++) + "次"); } }
对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
语法:
do { // 代码语句 }while(条件表达式);
/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { do { System.out.println("do...while执行..."); } while (false); } }
do...while
循环实现输出 1~5:/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { int i = 0; do { System.out.println("执行了" + (i + 1) + "次"); /** * i的变化值: 0,1,2,3,4 */ i++; } while (i < 5); } }
虽然所有循环结构都可以用 while 或者 do…while表示,但 Java 提供了另一种语句 —— for 循环,使一些循环结构变得更加简单。for循环执行的次数是在执行前就确定的。语法格式如下:
for(条件初始化①; 条件表达式②; 增量表达式④) { // 循环体语句③ }
使用for循环输出1~5:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { for (int i = 0; i < 5; i++) { /** * i的变化值: 0,1,2,3,4 */ System.out.println("执行了" + (i + 1) + "次"); } } }
其他写法:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo02 { public static void main(String[] args) { for (int i = 5; i >0 ; i--) { /** * i的变化值: 5,4,3,2,1 */ System.out.println("执行了" + i+ "次"); } } }
嵌套循环指的是循环的循环体语句是另一个循环。比如for循环里面还有一个for循环,就是嵌套循环。
总共的循环次数=外循环次数*内循环次数;
语法格式:
for(条件初始化①; 条件表达式②; 增量表达式④) { for(条件初始化①; 条件表达式②; 增量表达式④) { // 循环体语句③ } }
循环体可以无限嵌套,但是循环体嵌套层次越深,那么代码的执行效率将会非常低;
循环嵌套练习:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo03 { public static void main(String[] args) { // 外层循环控制行 for (int i = 0; i < 6; i++) { // 内层循环控制列 for (int j = 0; j < 8; j++) { // 不要换行 System.out.print("*"); } // 一次外层循环执行完毕时进行换行(外层循环执行多次那么就会有多少行) System.out.println(); } } }
tips:不仅是for循环可以嵌套,while、do…while这些循环一样是可以进行嵌套的;不仅如此,这些循环都可以相互嵌套,比如for里面有个while,while里面有个do…while,do…while里面又有一个for…
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。break 跳出最里层的循环,并且继续执行该循环下面的语句。
/** * @author lscl * @version 1.0 * @intro: break语句 */ public class Demo04 { public static void main(String[] args) { for (int i = 0; i < 10; i++) { if (i == 5) { // i==5的时候跳出循环 break; } System.out.println(i); } } }
break的作用一般是提前结束循环,或者是满足某个条件时手动结束循环
continue 作用是让程序立刻跳转到下一次循环的迭代。在 for 循环中,continue 语句使程序立即跳转到更新语句。在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
/** * @author lscl * @version 1.0 * @intro: continue语句 */ public class Demo05 { public static void main(String[] args) { for (int i = 0; i < 10; i++) { if (i == 5) { // i==5的时候跳出本次循环,继续下一次循环 continue; } System.out.println(i); } } }
continue的作用是结束本次循环,继续下一次循环;
数组是编程语言中非常常见的一种数据结构,是一种容器,用于存储多个相同类型的数据(元素)。在数组中,会为每一个元素分配一个下标(也叫索引),该下标默认从0开始,一直自增累加,我们可以通过下标来访问数组中的任意元素;
总结:数组就是一个容器,能够帮我们存储很多相同类型的数据;
前面提到过,数组就是一个容器,可以存储很多相同类型的数据;此外,数字的长度是固定的,最大下标默认为长度-1
如图所示:
数组特点:
动态初始化,只指定数组的长度,由系统为数组的每个元素分配初始值;
数组存储的数据类型[] 数组名字=new 数组存储的数据类型[长度]; int[] arr=new int[3];
tips:数组的长度一旦指定,不能更改
静态初始化,创建数组时,显式的指定数组元素的初始值,数组的长度由系统根据元素的格式来决定;
数据类型[] 数组名称=new 数据类型[]{元素1,元素2,元素3....}; int[] arr=new int[]{3,5,6};
tips:数组已经给定了元素,就不能再指定长度了
数据类型[] 数组名称={元素1,元素2,元素3}; int[] arr={1,34,65};
tips:即指定长度又给定元素;
直接输出数组名,输出的是该数组在内存中的内存地址值[I@1b6d3586
访问格式
数组名[索引];
示例:
arr[0];
/** * @author lscl * @version 1.0 * @intro: */ public class Demo01 { public static void main(String[] args) { // 定义数组 int[] arr = {520, 521, 1314}; /* 输出: [I@1540e19d [: 表示数组 I: 表示int类型数组, D表示double类型数组 @: 没有什么用(分割作用) 1540e19d: 数组在内存中的地址 */ System.out.println(arr); // 通过索引访问数组中的元素 System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); //通过索引修改数组中的元素 arr[1]=20; // 输出20 System.out.println(arr[1]); } }
数组的长度属性: 每一个数组都具有一个length
属性,该属性的值为当前数组的元素个数,也就是数组的长度,通过数组名.length
,可获取当前数组的长度值,返回的是一个int数,由此可以推断出,数组的最大索引值为length-1
;
/** * @author lscl * @version 1.0 * @intro: */ public class Demo02 { public static void main(String[] args) { int[] arr = {1, 4, 7, 2, 5, 8, 3, 6, 9}; //打印数组的长度: 9 System.out.println(arr.length); } }
遍历数组的意思就是对数组整个数据的一个搜索,通过数组的长度属性我们可以知道数组里面到底有多少个元素,使用循环语句便可以逐个取出:
public static void main(String[] args) { int[] arr=new int[]{11,22,33,44}; System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); }
以上代码是可以将数组中每个元素全部遍历出来,但是如果数组元素非常多,这种写法肯定不行,因此我们需要改
造成循环的写法。数组的索引是 0
到 lenght-1
,可以作为循环的条件出现。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo03 { public static void main(String[] args) { int[] arr = new int[]{11, 22, 33}; /* System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); */ //以上代码的问题:如果数组有几万个元素,我们打印就需要写几万行 //我们发现上面的代码是重复的代码,只有arr[]中的数字是变化的 //对于重复的代码我们可以用循环来解决 for (int i = 0; i < 3; i++) { System.out.println(arr[i]); } //以上代码看似非常好,但是不通用,如果数组元素多或少i<4;这个4不是固定的 //数组最小索引:0 //数组最大索引:arr.length - 1 //将4替换成arr.length,从0打印到arr.length-1 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }
不同循环遍历数组:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo03 { public static void main(String[] args) { int[] arr = {1, 4, 7, 2, 5, 8}; } /** * for循环遍历数组 * @param arr */ public static void print1(int[] arr){ for (int i = 0; i < arr.length; i++) { /** * i的变化: 0,1,2,3,4,5 */ System.out.println(arr[i]); } } }
/** * while循环遍历数组 * @param arr */ public static void print2(int[] arr){ // 定义数组索引,从0开始 int i=0; while (i<arr.length){ System.out.println(arr[i]); // 每次循环i自增1 i++; } }
/** * do...while循环遍历数组 * * @param arr */ public static void print3(int[] arr) { // 定义数组索引,从0开始 int i=0; do { System.out.println(arr[i]); // 每次循环i自增1 i++; }while (i<arr.length); }
观察如下代码:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo07 { public static void main(String[] args) { // 数组长度为3,最大索引为3-2=1 int[] arr = {1, 4, 7}; System.out.println(arr[3]); } }
创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此我们不能访问数组中不存在的索引,程序运行后,将会抛出 ArrayIndexOutOfBoundsException
数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo08 { public static void main(String[] args) { int[] arr = {1, 4, 7}; arr=null; System.out.println(arr[1]); } }
arr = null
这行代码,意味着变量arr将不会在保存数组的内存地址,也就不允许再操作数组了,因此运行的候会抛出 NullPointerException
空指针异常。
内存是计算机中的重要原件,临时存储区域,作用是运行程序。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。
Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
区域名称 | 作用 |
---|---|
寄存器 | 给CPU使用,和我们开发无关 |
本地方法栈 | JVM在使用操作系统功能的时候使用,和我们开发无关 |
方法区 | 存储可以运行的class文件,包含类的一些基本信息、常量、静态变量等 |
堆内存 | 存储对象或者数组,通过new创建的,都存储在堆内存 |
方法栈(虚拟机栈) | 也叫虚拟机栈,VM栈,方法运行时使用的内存,所有方法调用时,都会进栈执行。比如main方法运行时,就会进如方法栈中执行。 |
/** * @author lscl * @version 1.0 * @intro: */ public class Demo04 { public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr); // [I@1540e19d arr[1] = 8; System.out.println(arr[0]); } }
以上方法执行,输出的结果是[I@1540e19d
,这个是什么呢?是数组在内存中的地址。new出来的内容,都是在堆内存中存储的,而方法中的变量arr保存的是数组的地址。 输出arr[0],就会输出arr保存的内存地址中数组中0索引上的元素
public static void main(String[] args) { int[] arr1=new int[2]; int[] arr2=new int[3]; System.out.println(arr1); System.out.println(arr1[0]); System.out.println(arr1[1]); System.out.println(arr2); System.out.println(arr2[0]); System.out.println(arr2[1]); System.out.println(arr2[2]); arr1[0]=100; arr2[0]=200; System.out.println("----------------"); System.out.println(arr1); System.out.println(arr1[0]); System.out.println(arr1[1]); System.out.println(arr2); System.out.println(arr2[0]); System.out.println(arr2[1]); System.out.println(arr2[2]); }
/** * @author lscl * @version 1.0 * @intro: */ public class Demo06 { public static void main(String[] args) { int[] arr1 = {100, 200, 300}; System.out.println(arr1); System.out.println(arr1[0]); System.out.println(arr1[1]); System.out.println(arr1[2]); int[] arr2 = arr1; arr2[0] = 111; arr2[1] = 222; arr2[2] = 333; System.out.println("---------"); System.out.println(arr1); System.out.println(arr1[0]); System.out.println(arr1[1]); System.out.println(arr1[2]); System.out.println(arr2); System.out.println(arr2[0]); System.out.println(arr2[1]); System.out.println(arr2[2]); } }
以前的方法中我们学习了方法的参数和返回值,但是使用的都是基本数据类型。那么作为引用类型的数组能否作为方法的参数进行传递呢,当然是可以的。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo09 { public static void main(String[] args) { int[] arr = new int[]{1, 2, 3, 4, 5}; System.out.println("main方法中的arr: " + arr); //[I@1b6d3586 print(arr); } public static void print(int[] arr) { System.out.println("print方法中的arr: " + arr); //[I@1b6d3586 for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + ","); } } }
/** * @author lscl * @version 1.0 * @intro: */ public class Demo10 { public static void main(String[] args) { //调用getArr方法接收方法返回值,接收到的是数组的内存地址值 int[] arr = getArr(); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } public static int[] getArr() { int[] arr = {12, 54, 32}; // 返回数组的的内存地址值 return arr; } }