流程控制语句
流程控制即控制流程,具体指控制程序的执行流程,而程序的执行流程分为三种结构:顺序结构(之前我们写的代码都是顺序结构)、分支结构(用到if判断)、循环结构(用到while与for)。
顺序结构
顺序结构语句是Java程序默认的执行流程,按照代码的先后顺序,从上到下依次执行。
分支结构
if
if语句的第一种格式
if(关系表达式){
语句体;
}
执行流程
1首先计算关系表达式的值
2如果关系表达式的值为true就执行语句体
3如果关系表达式的值为false就不执行语句体
4继续执行后面的其他语句
注意:
1大括号的开头可以另起一行书写,但是建议写在第一行的末尾
2在语句体中,如果只有一句代码,大括号可以省略不写
3如果对一个布尔类型的变量进行判断,不要用==号
if语句的第二种格式
if(关系表达式){
语句体1;
}else{
语句体2;
}
执行流程
1首先计算关系表达式的值
2如果关系表达式的值为true就执行语句体1
3如果关系表达式的值为false就执行语句体2
4继续执行后面的其他语句
if语句的第三种格式
if(关系表达式1){
语句体1;
}else if(关系表达式2){
语句体2;
}
...
else{
语句体n+1;
}
执行流程
1首先计算关系表达式1的值
2如果为true就执行语句体1;如果为false就计算关系表达式2的值
3如果为true就执行语句体2;如果为false就计算关系表达式3的值
4...
5如果所以关系表达式结果都为false,就执行语句体n+1.
switch
switch(表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
执行流程
1首先计算表达式的值
2依次和case后面的值进行比较,如果有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
3如果所有的case后面的值和表达式的值都不匹配,就会执行default里面的语句体,然后结束整个switch语句。
格式说明
1表达式:(将要匹配的值)取值为byte,short,int,char.JDK5以后可以是枚举,JDK7以后可以是String。
2case:后面跟的是要和表达式进行比较的值(被匹配的值)。
3break:表示中断,结束的意思,用来结束switch语句。
4default:表示所有情况都不匹配的时候,就执行该处的内容,和if语句的else相似。
5case后面的值只能是字面量,不能是变量
6case给出的值不允许重复
switch其他知识点
default的位置和省略
位置:default不一定是写在最下面的,我们可以写在任意位置,只不过习惯会写在最下面
省略:default可以省略,语法不会有问题,但是不建议省略。
case穿透
就是语句体中没有写break导致的
执行流程:
首先还是会拿着小括号中表达式的值跟下面的每一个case进行匹配
如果匹配上了,就会执行对应的语句体,如果此时发现了break,那么结束整个switch语句
如果没有发现break,那么程序会继续执行下一个case的语句体,一直遇到break或者右大括号为止
switch新特性
switch语句内代码如果只有一行,大括号可以省略不写。
JDK12以后,switch格式可以简写
import java.util.Scanner;
public class Hello {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
System.out.println("请输入一个星期数字:");
int i = sc.nextInt();
switch(i){
case 1,2,3,4,5-> System.out.println("工作日");
case 6,7-> System.out.println("休息日");
}
}
}
switch和if第三种格式各自的使用场景
if的第三种格式:一般用于对范围的判断
switch:把有限个数据一一列举出来,让我们任选其一
循环结构
for循环
格式
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
执行流程
1执行初始化语句
2执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,执行循环体语句
3执行条件控制语句
4回到2继续执行条件判断语句
注意
1求和的变量不能定义在循环的里面,因为变量只在所属的打括号中有效
2如果我们把变量定义在循环的里面,那么当前变量只能在本次循环中有效。
当本次循环结束之后,变量就会从内存中消失
第二次循环开始的时候,又会重新定义一个新的变量
while循环
格式
初始化语句;
while(条件判断语句){
循环体语句;
条件控制语句;
}
执行流程
1执行初始化语句
2执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,执行循环体语句
3执行条件控制语句
4回到2继续执行条件判断语句
for与while的区别
相同点:运行规则都是一样的
区别:
for循环中,控制循环的变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到
while循环中,控制循环的变量,对于while循环来说不归属其语法结构中,在while循环结束后,该变量还可以继续使用
for和while在用法中的区别
for循环中:知道循环次数或者循环的范围
while循环:不知道循环的次数和范围,只知道循环的结束条件
练习:世界最高山峰是珠穆朗玛峰(8844.43米=8844430毫米),假如我有一张足够大的纸,它的厚度是0.1毫米。请问,我折叠多少次,可以折成珠穆朗玛峰的高度?
public class Hello {
public static void main(String[] args) {
double i =0.1;
double a =0;
while(i<=8844430){
i=i*2;
a+=1;
}
System.out.println(a);
}
}
练习:回文数,正序倒序都一样的数字,是回文数打印true,否则false。
import java.util.Scanner;
public class Hello {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
System.out.println("请输入一个数:");
int i =sc.nextInt();
int sum =i;
int a =0;
while(i!=0){
//取个位
int ge =i%10;
a=a*10+ge;
i=i/10;
}
System.out.println(a==sum);
}
}
练习:给你两个数,一个被除数一个除数,得出商和余数,不允许使用*,/,%运算符。
import java.util.Scanner;
public class Hello {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
System.out.println("请输入两个数:");
int sum = 0;
int a = sc.nextInt();
int b = sc.nextInt();
while(a>=b){
a=a-b;
sum++;
}
System.out.println("商为:" + sum +'\n' + "余数为:" +a);
}
}
do...while循环
格式:先执行后判断
初始化语句;
do{
循环体语句;
条件控制语句;
}while(条件判断语句)
无限循环
循环一直停不下来。
for(;;){
System.out.println("学习");
}
while(true){
System.out.println("学习");
}
do{
System.out.println("学习");
}while;
注意:无限循环的下面不能再写其他代码了,因为循环永远停不下来,那么下面的代码永远执行不到。
跳转控制语句
1continue:跳过本次循环,继续执行下次循环
public class Hello {
public static void main(String[] args) {
for(int i=1;i<=5;i++){
if(i==3){
//结束本次循环,继续下次循环
continue;
}
System.out.println("老虎正在吃第" + i +"个包子");
}
}
}
2break:结束整个循环
public class Hello {
public static void main(String[] args) {
for(int i=1;i<=5;i++){
if(i==3){
//结束整个循环
break;
}
System.out.println("老虎正在吃第" + i +"个包子");
}
}
}
练习
练习一:逢7过
朋友聚会的时候可能会玩一个游戏,逢7过。游戏规则:从任意一个数字开始报数,当你要报的数字是包含7或者是7的倍数时都要说:过。需求:使用程序在控制台打印出1~100之间的满足逢7必过规则的数据。
public class Hello {
public static void main(String[] args) {
for (int i = 1;i<=100;i++){
if(i%7==0 || i%10==7 || i/10==7){
System.out.println("过");
continue;
}
System.out.println(i);
}
}
}
练习二:求平方根
需求:键盘录入一个大于等于2的整数x,计算并返回x的平方根,结果只保留整数部分,小数部分将被舍去。
import java.util.Scanner;
public class Hello {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个大于等于2的数:");
int number = sc.nextInt();
for (int i = 0; i < number; i++) {
if(i*i==number){
System.out.println("该数的平方根就是:" + i);
break;
}else if(i*i>number){
System.out.println("该数平方根的整数部分是:" + (i-1));
break;
}
}
}
}
练习三:求质数
需求:键盘录入一个正整数x,判断该整数是否为一个质数。
import java.util.Scanner;
public class Hello {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个正整数:");
int number = sc.nextInt();
boolean a =false;
for (int i = 2; i < number; i++) {
if(number%i==0){
System.out.println("该数不是质数");
break;
}
}
}
}
获取随机数
Java帮我们写好了一个类叫Random,这个类就可以生成一个随机数。
1导包---Random这个类在哪
import java.util.Random;
导包的动作必须出现在类定义的上边
2创建对象---表示我要开始用Random这个类了
Random r = new Random();
上面这个格式里,只有r是变量名,可以变,其他的都不允许变
3生成随机数---真正开始干活
int number = r.nextInt(随机数的范围);
上面这个格式里面,只有number是变量名。可以变,其它的都不允许变。
注意:生成的随机数从0开始,顾头不顾尾。
如果想生成任意范围的随机数,方法如下
比如生成7-15之间的随机数
1让这个范围头尾都减去一个数,让这个范围从0开始,-7 0~8
2尾巴+1 8+1=9
3最终结果:再加上第一步减去的值
import java.util.Random;
public class Hello {
public static void main(String[] args) {
Random s = new Random();
int i = s.nextInt(9)+7;
System.out.println(i);
}
}
练习四:猜数字小游戏
需求:程序自动生成一个1-100之间的随机数字,使用程序实现猜出这个数字是多少?
import java.util.Random;
import java.util.Scanner;
public class Hello {
public static void main(String[] args) {
Random s = new Random();
Scanner sc = new Scanner(System.in);
int i = s.nextInt(100)+1;
while(true){
System.out.println("请输入你猜的数字:");
int a =sc.nextInt();
if(i>a){
System.out.println("猜小了");
}else if(i<a){
System.out.println("猜大了");
}else{
System.out.println("恭喜你,猜中了");
break;
}
}
}
}
注意:生成随机数的代码 int i = s.nextInt(100)+1;不能写在循环的里面,否则每一次都会产生一个新的随机数。
数组
数组的介绍
数组:指的是一种容器,可以用来存储同种数据类型的多个值。
数组容器在存储数据的时候,需要结合隐式转换考虑。
例如:int类型的数组容器(byte short int)(不可以boolean,double)
例如:double类型的数组容器(byte short int long float double)
建议:容器的类型和存储的数据类型保持一致
数组的定义与静态初始化
数组的定义
格式一
数据类型 [] 数组名
例如:int [] array
格式二
数据类型 数组名 []
例如:int array []
数组的初始化
初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
静态初始化
完美格式
数据类型[]数组名=new数据类型[]{元素1,元素2,元素3...};
范例:int[]array = new int[]{11,22,33};
范例:double[]array2 = new double[]{11.1,22.2,33.3};
简化格式
数据类型[]数组名={元素1,元素2,元素3...};
范例:int[]array ={11,22,33};
范例:double[]array2 ={11.1,22.2,33.3};
此时如果打印array,会得到数组的地址值。数组的地址值表示数组在内存中的位置。
扩展:解释一下地址值的格式含义 [I@27d6c5e0
[:表示当前是一个数组
i:表示当前数组里面的元素都是int类型的
@:表示一个间隔符号(固定格式)
27d6c5e0:才是数组真正的地址值(十六进制)
平时我们会习惯的把这个整体叫做数组的地址值
动态初始化
动态初始化:初始化只指定数组长度,由系统为数组分配初始值
格式:数据类型[]数组名 = new数据类型[数组长度];
范例:int[]arr = new int[3]
Strig[]arr = new String[50];
arr[0] = "zhangsan"
数组默认初始化值的规律
整数类型:默认初始化值0
小数类型:默认初始化值0.0
字符类型:默认初始化值'\u0000' 空格
布尔类型:默认初始化值false
引用数据类型:默认初始化值null
数组动态初始化和静态初始化的区别
动态初始化:手动指定数组长度,由系统给出默认初始化值
只明确元素个数,不明确具体数值,推荐使用动态初始化
举例:使用数组容器来存储键盘录入的5个整数
int[]arr = new int[5];
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度
需求中已经明确了要操作的具体数据,直接静态初始化即可
举例:将全班的学生成绩存入数组中99 88 100
int[]arr ={99,88,100};
数组元素访问
格式:数组名[索引]
索引:也叫做下标,角标。
索引的特点:从0开始,逐个+1增长,连续不间断
1获取数组里面的元素
格式:数组名[索引]
int[]arr = {1,2,3,4,5};
获取数组的第一个元素
int number = arr[0];
System.out.println(number); //1
或者直接打印
System.out.println(arr[1]); //2
2把数据存储到数组中
格式:数组名[索引] = 具体的数据/变量;
细节:一旦覆盖之后,原来的数据就不存在了。
arr[0] = 100;
System.out.println(arr[0]); //100
数组遍历
数组遍历:将数组中所有的内容取出来,取出来之后可以(打印,求和,判断...)
注意:遍历指的是取出数据的过程,不要局限的理解为,遍历就是打印。
在Java当中,关于数组的一个长度属性:length
调用方式:数组名.length
for (int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
扩展:自动快速生成数组的遍历方式,idea提供的
格式:数组名.fori
练习:定义一个数组,存储1~10,遍历数组得到每一个元素,统计数组里面一共有多少个能被3整除的数字
public class Hello{
public static void main(String[]args){
int[]arr = {1,2,3,4,5,6,7,8,9,10};
int sum = 0;
for (int i=0;i<arr.length;i++){
//i表示数组里面的每一个索引
//arr[i]表示数组里面的每一个元素
if(arr[i]%3==0){
sum++;
}
}
System.out.println(sum);
}
}
练习:定义一个数组,存储1~10,遍历数组得到每一个元素,如果是奇数*2,如果是偶数/2.
public class Hello{
public static void main(String[]args){
int[]arr = {1,2,3,4,5,6,7,8,9,10};
for (int i=0;i<arr.length;i++){
if(arr[i]%2==0){
arr[i]=arr[i]/2;
}else if(arr[i]%2!=0){
arr[i]=arr[i]*2;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
数组常见问题
当访问了数组中不存在的索引,就会引发索引越界异常。
数组常见操作
求最值
练习:找出最大值
public class Hello {
public static void main(String[] args) {
int[]arr = {11,44,55,3,79};
int max = arr[0];
for (int i = 0; i < arr.length; i++) { //开始条件i=1少一次无效循环
if(arr[i]>max){
max=arr[i];
}
}
System.out.println(max);
}
}
求和
随机生成10个1~100的数,求数据和,平均数,比平均数小的个数。
import java.util.Random;
public class Hello {
public static void main(String[] args) {
int[] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
int number = r.nextInt(100) + 1;
arr[i] = number;
}
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
int geshu =0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] < (sum / arr.length)) {
geshu++;
}
}
System.out.println("十个数字的和:" + sum + '\n' + "十个数字的平均数:" + (sum / 10) + '\n' + "比平均数小的个数为:" + geshu);
}
}
交换数据
定义一个数组,存入1,2,3,4,5按照要求交换索引对应的元素
交换前:1,2,3,4,5
交换后:5,2,3,4,1
public class Hello {
public static void main(String[] args) {
int[]arr = {1,2,3,4,5};
int temp =arr[0];
arr[0]=arr[4];
arr[4]=temp;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
首尾依次交换
public class Hello{
public static void main(String[]args){
int[]arr = {1,2,3,4,5};
for(int i =0,j = arr.length-1;i<j;i++,j--){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
for(int i = 0;i<arr.length;i++){
System.out.print(arr[i] + " ");
}
}
}
打乱数据
import java.util.Random;
public class Hello {
public static void main(String[] args) {
int[]arr = {1,2,3,4,5};
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
int number = r.nextInt(arr.length);
int temp = arr[i];
arr[i]=arr[number];
arr[number]=temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
数组的内存图
Java内存分配:栈,堆,方法区,本地方法栈,寄存器。
注意:从JDK8开始取消方法区,新增元空间。把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中。
栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行
堆:存储对象或者数组,new来创建的,都存储在堆内存
方法区:存储可以运行的class文件
本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
寄存器:给CPU使用,和我们开发无关
栈内存:程序的主入口(main方法)开始执行时会进栈,代码执行完毕会出栈。
堆内存:new出来的东西,在这块内存中开辟空间并产生地址,有地址值
数组内存图
方法
方法是程序中最小的执行单元。
重复的代码,具有独立功能的代码可以抽取到方法中。
可以提高代码的复用性,提高代码的可维护性。
例如下面的main方法。
public class Hello{
public static void main(String[] args) {
System.out.println("明天你好");
}
}
方法的格式
方法定义:把一些代码打包在一起
方法调用:方法定义后并不是直接运行的,需要手动调用才执行
最简单的方法定义
定义格式
public static void 方法名(){
方法体(就是打包起来的代码);
}
例如
public static void playGame(){
System.out.println();
}
调用格式
方法名();
例如
playGame();
例如
public class Hello{
public static void main(String[] args) {
//调用方法
playGame();
}
//定义一个方法(main方法的外面,类的里面)
public static void playGame(){
System.out.println("选英雄");
System.out.println("开局");
System.out.println("对线");
System.out.println("崩盘");
System.out.println("骂队友");
System.out.println("送人头");
System.out.println("GG");
}
}
带参数的方法定义
定义格式
单个参数
public static void 方法名(参数){......}
多个参数
public static void 方法名(参数1,参数2,......){.......}
例如
public static void getSum(int number1,int number2){.......}
调用格式
单个参数:方法名(参数);
例如:method(10);
例如:method(变量);
多个参数:方法名(参数1,参数2,...);
例如:getSum(10,20);
例如:getSum(变量1,变量2);
注意:方法调用时,参数的数量与类型必须与方法定义中小括号里面的变量一一对应,否则程序将报错。
public class Hello {
public static void main(String[] args) {
getSum(10,20);
}
public static void getSum(int sum1,int sum2){
int result = sum1 + sum2;
System.out.println(result);
}
}
形参和实参
形参:全称形式参数,是指方法定义中的参数
实参:全称实际参数,方法调用中的参数
带返回值方法的定义(完整定义格式)
定义格式
public static 返回值类型 方法名(参数){
方法体;
return 返回值;
}
范例
public static int getSum(int a,int b){
int c = a + b;
return c;
}
调用格式三种
直接调用:方法名(实参);
赋值调用:返回值类型 变量名 = 方法名(实参);
输出调用:System.out.println(方法名(实参));
public class Hello {
public static void main(String[] args) {
//直接调用,没有打印出来
C(1,2);
//赋值调用
int sum =C(1,2);
System.out.println(sum);
//输出调用
System.out.println(C(2,2));
}
public static int C(int a, int b){
int c = a+b;
return c;
}
}
练习:定义方法,比较两个长方体面积
public class Hello {
public static void main(String[] args) {
double sum1 = S(2.1,2.0);
double sum2 = S(2.1,2.0);
if(sum1==sum2){
System.out.println("两个长方体面积一样大");
} else if (sum1>sum2) {
System.out.println("第一个长方体面积比第二个大");
}else{
System.out.println("第一个长方体面积比第二个小");
}
}
public static double S(double a,double b){
double sum = a*b;
return sum;
}
}
方法的注意事项
方法不调用就不执行
方法和方法之间是平级关系,不能互相嵌套定义
方法的编写顺序和执行顺序无关()
方法的返回值类型为void,表示该方法没有返回值
没有返回值的方法可以省略return语句不写
如果要编写return,后面不能跟具体的数据
return语句下面,不能编写代码,因为永远执行不到,属于无效代码。
return关键字
方法没有返回值:可以省略不写。如果书写,表示结束方法。
方法有返回值:必须书写。表示结束方法和返回结果。
方法的重载
-
在同一个类中,定义了多个同名的方法,这些同名的方法具有同种的功能。
-
每个方法具有不同的参数类型或参数个数,这些同名的方法,就构成了重载关系。
-
简单记:同一个类中,方法名相同,参数不同的方法。与返回值无关。
参数不同:个数不同,类型不同,顺序不同。
(Java虚拟机会通过参数的不同来区分同名的方法)
练习:设计一个方法用于遍历数组,要求遍历的结果是在同一行,例如[11,22,33,44,55]
public class Hello {
public static void main(String[] args) {
int[]arr={11,22,33,44,55};
printArr(arr);
}
public static void printArr(int arr[]){
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length-1){
System.out.print(arr[i]);
}else{
System.out.print(arr[i] + ", ");
}
}
System.out.println("]");
}
}
练习:设计一个方法求数组的最大值,并返回最大值。
public class Hello{
public static void main(String[] args) {
int []arr={1,2,3,4,5,6,7};
System.out.println(ArrMax(arr));
}
public static int ArrMax(int []arr){
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i] > max){
max = arr[i];
}
}return max;
}
}
练习:定义一个方法判断数组中的某一个数是否存在,将结果返回到调用处。
public class Hello {
public static void main(String[] args) {
int []arr = {11,23,4,5,6,7};
boolean flag = contains(arr,23);
System.out.println(flag);
}
public static boolean contains(int []arr ,int number){
for (int i = 0; i < arr.length; i++) {
if(arr[i] ==number){
return true;
}
}return false;
}
}
注意:break和return的区别
return:其实跟循环没有什么关系,跟方法有关,表示结束方法,返回结果
如果方法执行到了return,那么整个方法全部结束,里面的循环也会随之结束。
break:其实跟方法没有什么关系,结束循环或者switch语句的。
练习:定义一个方法copyOfRange(int[]arr,int from,int to),将数组arr中从索引from(包含from)开始。到索引to结束(不包含to)的元素复制到新数组中,然后返回。
public class Hello {
public static void main(String[] args) {
int[]arr = {1,2,3,4,5,6,7,8,9};
int []copyArr = copyOfRange(arr,3,7);
for (int i = 0; i < copyArr.length; i++) {
System.out.print(copyArr[i] + " ");
}
}
public static int[] copyOfRange(int arr[],int from,int to) {
int[] newArr = new int[to - from];
int tag = 0;
for (int i = from; i < to; i++) {
newArr[tag] = arr[i];
tag++;
}
return newArr;
}
}
方法的内存
方法调用的基本内存原理
Java内存分配
栈:方法运行时使用的内存,方法进栈运行,运行完毕就出栈(先进后出)
堆:new出来的,都在堆内存中开辟了一个小空间
方法区:存储可以运行的class文件
本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
寄存器:给CPU使用,与我们开发无关
方法被调用之后就会进栈执行。
方法传递基本数据类型的内存原理
整数类型,浮点数类型,布尔类型,字符类型
基本数据类型变量中存储的是真实的数据。
内存的角度
基本数据类型:数据值是存储在自己的空间中
特点:赋值给其他变量,也是赋的真实的值
传递基本数据类型时,传递的是真实的数据,形参的改变,不影响实际参数的值。
方法传递引用数据类型的内存原理
引用数据类型变量中存储的是地址值
引用:使用了其他空间中的数据
内存的角度
引用数据类型:数据值是存储在其他空间中,自己空间中存储的是地址值
特点:赋值给其他变量,赋的是地址值。
传递引用数据类型时,传递的是地址值,形参的改变,影响实际参数的值。