java基础语法(从0开始到java方法)

文章目录

  • 1.第一个java程序
  • 2.数据的表示详解
    • 2.1 整数在计算机中的存储原理
    • 2.2 字符在计算机中的存储原理
    • 2.3 图片视频声音的存储原理
    • 2.4 数据的其他表示形式
    • 2.5 不同进制在Java程序中的书写格式
  • 3.数据类型详解
  • 4.数据类型转换
    • 4.1 自动类型转换
    • 4.2 强制类型转换
  • 4.运算符
    • 4.1 算术运算符
    • 4. 2 自增自减运算符
    • 4.3 赋值运算符
    • 4.4 关系运算符
    • 4.5 逻辑运算符
    • 4.6 三元运算符
    • 4.7 运算优先级
  • 5.分支结构
    • 5.1 if分支
    • 5.2 switch分支
    • 5.3 switch 注意事项
  • 6.循环结构
    • 6.1 for循环——格式和流程
    • 6.2 for循环案例1——求和
    • 6.3 for循环案例2——求奇数和
    • 6.4 while循环——格式和流程
    • 6.5 while循环案例——折纸案例
    • 6.6 do-while循环——格式和流程
    • 6.6 死循环
    • 6.7 循环嵌套
    • 6.8 跳转语句 break 、continue
    • 6.9 循环结构总结
  • 7.生成随机数
    • 7.1 如何产生一个随机数
    • 7.2 猜数字小游戏
  • 8.认识数组
    • 8.1. 什么数组
    • 8.2. 数组的应用场景
  • 9.数组的定义和访问
    • 9.1 数组的静态初始化
    • 9.2 数组的元素访问
    • 9.3 数组的遍历
    • 9.4 数组静态初始化案例
    • 9.5 数组的动态初始化
    • 9.6 数组动态初始化案例
  • 10.数组在计算机中的执行原理
    • 10.1 数组的执行原理,Java程序的执行原理
    • 10.2 多个变量指向同一个数组的问题
  • 11.数组专项练习
    • 11.1 数组求最值
    • 11.2 数组元素反转
    • 11.3 随机排名
  • 12.Debug调试工具
  • 13.方法概述
    • 13.1 方法是什么
    • 13.2 方法的执行流程
    • 13.3 定义方法的注意点
    • 13.4 使用方法的好处
  • 14.方法的其他形式
  • 15.方法使用常见的问题
  • 16.方法在计算机中的执行原理
    • 16.1 有返回值的方法,内存分析
    • 16.2 无返回值的方法,内存分析
  • 17.方法参数的传递机制
    • 17.1 参数传递的基本类型数据
    • 17.2 参数传递的是引用数据类型
  • 18.方法参数传递案例
    • 18.1 方法参数传递案例1
    • 18.2 方法参数传递案例2
  • 19.方法重载
  • 20.return单独使用

本文将为您介绍Java的基础语法,帮助初学者快速入门。我们将从Java的基本结构开始,包括类和对象的定义,以及如何使用Java的关键字和数据类型。然后,我们将深入探讨Java的控制流语句,如if-else、switch-case、循环等,这些是构建任何程序逻辑的基础。

1.第一个java程序

public class Main {  
    public static void main(String[] args) {  
        System.out.println("Hello world!");  
    }  
}

这段程序是Java语言编写的一个简单的程序,其目的是在控制台输出一段文本。下面是对这段代码的逐行分析:

  1. public class Main {:这行代码声明了一个名为Main的公共类。在Java中,每个应用程序都有一个主类,它包含程序的入口点。
  2. public static void main(String[] args) {:这是Java程序的主方法,是程序执行的起点。main方法是一个公共(public)的静态(static)方法,它不接受任何参数,也不返回任何值。String[] args是一个字符串数组,用于接收命令行参数。
  3. System.out.println("Hello world!");:这行代码使用System.out对象的println方法来在控制台打印字符串"Hello world!"System.out是Java的标准输出流,通常用于打印信息到控制台。
    整个程序的作用是创建一个Main类,然后在main方法中打印出"Hello world!"。这是一个非常基础的Java程序,通常用于教学和作为学习Java的起点。当你运行这个程序时,它会在控制台输出Hello world!

2.数据的表示详解

我们知道变量可以用来记录数据的。那么数据在计算机底层是以什么形式表示的呢?下面我们就学习一下数据在计算机中的底层原理。

2.1 整数在计算机中的存储原理

其实任何数据在计算机中都是以二进制表示的。那这里肯定有人问,什么是二进制啊?所谓二进制其实就是一种数据的表示形式,它的特点是逢2进1。
数据的表示形式除了二进制(逢2进1),八进制(逢8进1)、还有十进制(逢10进1)、十六进制(逢10进1)等。
对于二进制绝大多数同学,应该是非常陌生的。 没关系!来,大家跟着我的思路,你就知道二进制是怎么表示数据的了。

1.二进制中只有01两个数
	首先十进制的0和二进制的0是一样的,十进制的1和二进制的1也是 一样的。但是十进制中	  有2,但是二进制中就没有22.那么二进制是如何表示十进制的2呢?
	1
+	1		
——————————	
   10	  这里两个1相加,结果为2,由于二进制满21,所以最终结果10
   
3.那么二进制是如何表示十进制的3呢?
	前面我们已经知道二进制10表示十进制的2,那么二进制10+1就表示十进制的3啊!
	10
+    1
—————————
    11	 十进制的3对应的二进制是11

4.那么二进制是如何表示十进制4的呢?
	前面我们已经知道二进制11表示十进制的4,那么11+1就表示十进制的511
+    1
—————————
   100   十进制的5对应的二进制是100

你找到规律了吗? 你能不能依次写出5的二进制、6的二进制?

前面每算一个二进制数据都是采用+1的方式,逢2进1,一个一个算出来的。有没有更快的算出十进制对应二进制的方法呢? 这里学习一种方式:叫做除2取余法。

  • 除2取余法
1.怎么做呢?
	答:让十进制数据连续除以2,直到商为0,余数反转

2.举例1:把十进制6转换为二进制	
			商	余数
	6/2     3    0
    3/2		1	 1
    1/2		0	 1
    然后把余数反转:6对应的二进制是110
    
3.举例2: 把十进制13转换为二进制
			商	余数
	13/2	6	 1
    6/2		3	 0
    3/2	 	1 	 1
    1/2		0	 1
    然后把余数反转:10对应的二进制是1101
    
4.练习1:你能把十进制7转换为二进制吗?
	自己试试吧!

关于变量记录的数据在计算机中如何表示我们就先学习到这里。

  • 计算机的最小存储单位

前面我们已经知道计算机表示数据是用二进制来的, 这里我又要抛出一个问题来了! 我现在想要在计算机中存储一个整数6,转换为二进制是110,那么计算机中只是存110吗三位数字吗? 其实不是的,计算机中最小的存储单位是字节(Byte),一个字节占8位(bit),也就是说即使这个数据不足8位也需要用8位来存储。

2.2 字符在计算机中的存储原理

通过上一节的学习,我们知道了整数是如何在计算机中如何存储的?那么字符在计算机中是如何存储的呢?

其实字符并不是直接存储的,而是把每一个字符编为一个整数,存储的是字符对应整数的二进制形式。美国人搞了一套字符和整数的对应关系表,叫做ASCII编码表。

ASCII编码表中字符编码的规律:
	1.字符0对应48,后面的1,2,3,4...9 对应的十进制整数依次往后顺延
	2.字符a对应97,后面的b,c,d,e...z 对应的十进制整数依次往后顺延
	3.字符A对应65,后面的B,C,D,E...Z 对应的十进制整数依次往后顺延

需要注意的是,在ASCII编码表中是不包含汉字的。汉字在其他编码表中,后面我们会单独介绍。关于字符在计算机中的存储学到这就可以了。

2.3 图片视频声音的存储原理

  • 图片的存储

通过上面的学习我们已经知道整数和字符是如何存储的,最终都是要转换为二进制数据的,对吧! 那图片、声音、视频又是如何存储的呢?我们也来了解一下

我们从图片开始,如果你把一张图片不断的放大,你会看到有马赛克的效果。你会发现图片中的每一个细节是由一个一个的小方格组成的,每一个小方格中其实就是一种颜色。任何一种颜色可以使用三原色来表示,简称RGB,其中R(红色),G(绿色),B(蓝色),而RGB中每一种颜色又用一个字节的整数来表示,最小值是0最大值是255

RGB0,0,0)表示黑色
RGB255,255,255)表示白色
RGB255,0,0) 表示红色
RGB255,255,0) 表示红色和绿色混合为黄色
RGB255,0,255) 表示红色和蓝色混合为紫色
...

你在画图板的颜色编辑器中可以通过指定RGB的值,来调整得到任意的颜色。一张图片实际上就是有很多个小方块的颜色组成的,而每一种颜色又是由RGB三原色的整数表示的,整数最终会转换为二进制进行存储。

  • 视频的存储

实际上视频和图片是一样的,把多张图片连续播放,在一秒钟内连续播放24张以上,由于人眼存在视觉暂留现象,人眼感受不到画面切换的时间间隔,就认为是连续的视频了。

  • 声音的存储

了解过物理的同学肯定知道,声音是以波的形式传播的。我们可以把声波在表示在一个坐标系上,然后在坐标系上取一些点,把这些点的坐标值以二进制的形式存储到计算机中,这就是声音的存储原理。

2.4 数据的其他表示形式

  • 二进制到十进制的转换

前面我们学习了十进制可以转二进制,采用的是除2取余法,那么我们反过来能不能把二进制转换为十进制呢?

这里给大家介绍一种计算方式叫做:8421码

为了便于理解,我们先在看一下十进制怎么转十进制,主要是为了让大家看到演化过程。

1.十进制转十进制
	比如我们把12345进行分解:
        12345 = 10000 + 2000 + 300 + 40 + 5
              = 1*10^4 + 2*10^3 + 3*10^2 + 5*10^0
	我们发现:
		在十进制中如果把十进制的每一位从右往左从0开始编一个号,假设这一位数字是a,			那么这一位数表示的值就是:a*10^n;
	
----------------------------------------------------------------------2.二进制转十进制:
	类比十进制:
		如果把二进制的每一位从从右往左0开始编一个号用n表示,假设二进制的每一位是a,
		那么这一位表示的十进制值是:a*2^n
		
	1)假设二进制的每一位都是1128	64	32	16	8	4	2	1	每一位表示的十进制:a*2^n
		7	6	5	4	3	2	1	0	编号:n
		1	1	1	1	1	1	1	1   二进制的每一位:a
	
        二进制		 十进制
        11111111 = 1*2^7  + 1*2^6 + 1*2^5 + ... + 1*2^0
                 = 128    + 64    + 32    + ... + 1
                 = 255
    
    2)假设二进制的为0010001
    	128	64	32	16	8	4	2	1	每一位表示的十进制:a*2^n
    	7	6	5	4	3	2	1	0	编号:n
    	0	0	1	0	0	0	0	1	二进制的每一位:a
    
    	二进制				十进制
    	00001101 = 0*2^7 + 0*2^6 + 1*2^5 + ... + 1*2^0
    			 = 0     + 0     + 32 	 + ... + 1
    			 = 33

    3)8421码:从右往左给二进制的每一位数依次按照1 2 4 8...标记
    	128	64	32	16	8	4	2	1
    	0	0	1	0	0	0	0	1
    	-----------------------------
    	只需要将1位上的数字加起来,就是二进制对应的十进制
    	
    	二进制			  十进制
    	00001101 = 		8+4+1
    			 = 		13
    	
    	0000111	 =      4+2+1
    			 = 		7
    	
    	0001111  =      8+4+2+1
    			 =      25
  • 二进制转八进制

前面我们说计算机中数据都是采用二进制来存储的,但是二进制阅读和编写起来都不太方便。为了便于阅读和书写,又推出了八进制、十六进制。

1.运算规则:
	把二进制的每三位一组合,然后对每三位用8421码进行计算,最后拼接到一起
	原因:因为111,的值是7, 再大满7就需要往进位了。 
	
2.把二进制11001110转换为八进制数据
	01	100 001		二进制每三位一组合
    1	4	1		每一组进行8421码运算
    ----------
    八进制:141
  • 二进制转十六进制
1.运算规则:
	把二进制的每四位一组合,然后对每四位用8421码进行计算,最后拼接到一起
	原因:因为1111,的值是15, 再大116了就需要往进位了。 
	
2.举例:把二进制11001110转换为十六进制数据
	0110 0001		二进制每四位一组合
    6	 1			每一组进行8421码运算
    ----------
    十六进制:61
    
3.练习:把111100转换为十六进制
	0011 1100
    3	 12		由于十六进制中有a,b,c,d,e,f分别表示10,11,12,13,14,15
    -----------
    十六进制:3c

2.5 不同进制在Java程序中的书写格式

System.out.pirntln('a'+1); //98
System.out.pirntln(0b01100001); //97
System.out.pirntln(0141); //97
System.out.pirntln(0x61); //97

3.数据类型详解

我们学过了变量的定义,在定义变量时我们是要声明数据类型的,这里的数据类型是用来规定变量存储什么类型的数据

比如int a = 10; 这里的int就是限制变量只能存储整数; 除了int这种数据类型Java还提供了很多其他的数据类型。Java的数据类型整体上来说分为两大类: 基本数据类型引用数据类型

需要我们注意的是,随便写一个整数或者小数的字面量,它也是有默认数据类型的

- 比如23,它默认就为int类型;如果加上后缀L,则为long类型;
- 比如23.8,它默认为double类型;如果加上后缀F,则为float类型;

下面定义各种类型的变量,将这8种基本数据类型都用一下。

public class TypeDemo1 {
    public static void main(String[] args) {
        // 目标:掌握8种基本数据类型,用来定义变量。
        // 1、整型
        byte number = 98;
        System.out.println(number);

        short number2 = 9000;

        int number3 = 12323232; // 默认

        // 注意:随便写一个整型字面量,默认是int类型的,73642422442424虽然没有超过long的范围,但是它超过了本身int的范围了。
        // 如果希望随便写一个整型字面量是long类型的,需要在其后面加上L/l
        long number4 = 73642422442424L;

        // 2、浮点型
        //注意:
        //随便写一个小数字面量,默认当成double类型对待的,
        //如果希望这个小数是float类型的,需要在后面加上:F/f
        float score1 = 99.5F;
        double score2 = 99.8; // 默认定义方案。

        // 3、字符型
        char ch1 = 'a';
        char ch2 = '中';
        char ch3 = '国';

        // 4、布尔型
        boolean b1 = true;
        boolean b2 = false;

        // 引用数据类型:String.
        // String代表的是字符串类型,定义的变量可以用来记住字符串。
        String name = "黑马";
        System.out.println(name);
    }
}

4.数据类型转换

4.1 自动类型转换

接下来我们来学习类型转换的知识。为什么要学习类型转换呢?因为在我们实际开发中可能存在将某种类型变量的值,赋值给另一个类型的变量;也可能存在多种数据类型的数据一起运算的情况。

在以上情况中,其实都会涉及到类型转换。类型转换的形式总体分为2种,一种是自动类型转换,一种是强制类型转换。 这里先学习自动类型转换

  • 什么是自动类型转换呢?
答:自动类型转换指的是,数据范围小的变量可以直接赋值给数据范围大的变量
	byte a = 12; 
	int b = a; //这里就发生了自动类型转换(把byte类型转换int类型)
  • 自动类型转换的原理是怎样的?
答:自动类型转换其本质就是在较小数据类型数据前面,补了若干个字节

下面我们通过代码演示一下,自动类型转换的各种形式。

public class TypeConversionDemo1 {
    public static void main(String[] args) {
        // 目标:理解自动类型转换机制。
        byte a = 12;
        int b = a; // 发生了自动类型转换了
        System.out.println(a);
        System.out.println(b);

        int c = 100; // 4
        double d = c;// 8 发生了自动类型转换了
        System.out.println(d);

        char ch = 'a'; // 'a' 97 => 00000000 01100001
        int i = ch; // 发生了自动类型转换了 =>  00000000 00000000  00000000 01100001
        System.out.println(i);
    }
}
  • 表达式的自动类型转换

自动类型转换还有另外一种形式,就是表达式的自动类型转换。所谓表达式指的是几个变量或者几个数据一起参与运算的式子。

如果同一个表达式中,出现不同类型的变量或者数据一起运算,这种情况下运算结果是一个什么数据类型呢?需要遵守下面的两条运算规则:

1.多种数据类型参与运算,其结果以大的数据类型为准
2.byte,short,char 三种类型数据在和其他类型数据运算时,都会转换为int类型再运算

接下来我们来看代码演示,自己试一试

public class TypeConversionDemo2 {
    public static void main(String[] args) {
        // 目标:掌握表达式的自动类型转换机制。
        byte a = 10;
        int b = 20;
        long c = 30;
        long rs = a + b + c;
        System.out.println(rs);

        double rs2 = a + b + 1.0;
        System.out.println(rs2);
		
        byte i = 10;
        short j = 30;
        int rs3 = i + j;
        System.out.println(rs3);

        // 面试笔试题: 即使两个byte运算,结果也会提升为int
        byte b1 = 110;
        byte b2 = 80;
        int b3 = b1 + b2;
        System.out.println(b3);
    }
}

4.2 强制类型转换

前面我们学习了自动类型转换,我们知道可以将数据类型小的数据可以直接赋值给数据范围大的变量。 那反过来,能不能将数据范围大的数据直接赋值给数据范围小的变量呢? 答案是会报错。

因为数据范围大的数据,赋值给数据范围小的变量,它有可能装不下;就像把一个大桶的水倒入一个小桶中,有溢出的风险。

  • 什么是强制类型转换

但是你强行将范围大的数据,赋值给范围小的变量也是可以的,这里就需要用到强制类型转换。下面是强制类型转换的格式

目标数据类型  变量名  =  (目标数据类型)被转换的数据;

下面是强制类型转换的代码演示

public class TypeConversionDemo3 {
    public static void main(String[] args) {
        // 目标:掌握强制类型转换。
        int a = 20;
        byte b = (byte) a;  // ALT + ENTER 强制类型转换。
        System.out.println(a);
        System.out.println(b);

        int i = 1500;
        byte j = (byte) i;
        System.out.println(j);

        double d = 99.5;
        int m = (int) d; // 强制类型转换
        System.out.println(m); // 丢掉小数部分,保留整数部分
    }
}
  • 强制类型转换的原理

    强制类型转换的原理,其实就是强行把前面几个字节砍掉,但是有数据丢失的风险

到这有关数据类型和数据类型转换的内容,我们就学习完了。大家能够知道什么时候会发生自动类型转换,以及如何进行强制类型转换就可以了。

4.运算符

接下来,讲解一个在开发中用得很多的一块内容,叫做运算符。

大家知道计算机是用来处理数据的,处理数据就少不了对数据的计算,想要对数据进行计算就必须用到运算符。

运算符就是参与运算的符号。Java提供的运算符有很多种,可以分为算术下面几种

  • 基本算术运算符
  • 自增自减运算符
  • 赋值运算符
  • 关系运算符
  • 逻辑运算符
  • 三元运算符

4.1 算术运算符

先从最基本的算术运算符开始学习,算术运算符有 + - * / % ,其中*表示乘法,/表示除法,%表示取余数

需要我们注意以下几点

/: 两个整数相除,结果也是一个整数
%: 表示两个数相除,取余数

需要我们注意的是:+符号除了用于加法运算,还可以作为连接符。+符号与字符串运算的时候是用作连接符的,其结果依然是一个字符串

下面通过代码演示一下各种算术运算符的运算效果

public class OperatorDemo1 {
    public static void main(String[] args) {
        // 目标:掌握基本的算术运算符的使用。
        int a = 10;
        int b = 2;
        System.out.println(a + b);
        System.out.println(a - b);
        System.out.println(a * b); // 20
        System.out.println(a / b); // 5
        System.out.println(5 / 2); // 2.5 ==> 2
        System.out.println(5.0 / 2); // 2.5
        int i = 5;
        int j = 2;
        System.out.println(1.0 * i / j); // 2.5

        System.out.println(a % b); // 0
        System.out.println(3 % 2); // 1

        System.out.println("---------------------------------------");

        // 目标2:掌握使用+符号做连接符的情况。
        int a2 = 5;
        System.out.println("abc" + a2); // "abc5"
        System.out.println(a2 + 5); //  10
        System.out.println("itheima" + a2 + 'a'); // "itheima5a"
        System.out.println(a2 + 'a' + "itheima"); // 102itheima
    }
}

4. 2 自增自减运算符

接下来,学习一种比较常用的运算符:++--

++读作自增,--读作自减; 运算规则如下

需要我们注意的是,自增自减只能对变量进行操作,不能操作字面量。具体使用时也分为两种情况,如下:

1.单独使用:++或者--放在变量前面没有区别
	   int a =10; 
	    a++;  //11
		--a;  //10
		System.out.println(a); //10

2.混合使用:++或者--放在变量或者前面运算规则稍有不通过
	//++在后:先做其他事情,再做自增和自减
	int a = 10;
	int b = a++; //等价于 int b = a; a++; 

	//++在前:先自增或者自减,再做其他运输
	int x = 10;
	int y = --x; //等价于x--; int y = x;  

下面通过代码演示一下++--的用法

public class OperatorDemo2 {
    public static void main(String[] args) {
        // 目标:掌握自增自减运算符的使用。
        int a = 10;
        // a++; // a = a + 1
        ++a;
        System.out.println(a);

        // a--; // a = a - 1
        --a;
        System.out.println(a);

        // 自增自减只能操作变量不能操作字面量的,会报错!
      	//System.out.println(2++);

        System.out.println("--------------------------------------");

        int i = 10;
        int rs = ++i; // 先加后用
        System.out.println(rs);
        System.out.println(i);

        int j = 10;
        int rs2 = j++; // 先用后加
        System.out.println(rs2);
        System.out.println(j);
    }
}

4.3 赋值运算符

接下来,我们学习赋值运算符。基本的赋值运算符其实就是=号,意思就是把右边的数据赋值给左边的变量。

int a = 10; //将数据10赋值给左边的变量a

除了基本的赋值运算符,我们这里主要学习一下扩展的赋值运算符。有+= -= *= /= %=

我们以+=为例来看一下它的运算规则,其他的运算符运算同理分析即可

int a = 10;
//+=解析:在a原来记录值10的基础上累加5,将结果重新赋值给a; 
a+=5; 
//最终打印a的值为15
System.out.println(a); 

下面通过一个首发红包的例子给大家演示一下

public class OperatorDemo3 {
    public static void main(String[] args) {
        // 目标:掌握扩展赋值运算符的使用。
        // +=
        // 需求:收红包
        double a = 9.5;
        double b = 520;
        a += b;  // a = (double)(a + b);
        System.out.println(a);

        // -= 需求:发红包
        double i = 600;
        double j = 520;
        i -= j;  // i = (double)(i - j);
        System.out.println(i);

        int m = 10;
        int n = 5;
        // m *= n; // 等价形式: m = (int)(m * n)
        // m /= n; // 等价形式: m = (int)(m / n)
        m %= n;    // 等价形式: m = (int)(m % n)
        System.out.println(m);
    }
}

学完扩展赋值运算符的基本使用之后,接下来我们看一个面试题

问题1:下面的代码否有问题?
    byte x = 10;
    byte y = 30;
	x = x + y;  //这句代码有问题,因为两个byte类型数据相加,会提升为int类型;
	
问题2:下面的代码是否有问题?
	byte x = 10;
	byte y = 30;
	x+=3; //这句代码没有问题,因为这里有隐含的强制类型转换
		  //x+=3; 等价于 byte x = (byte)(x+y);

到这里赋值运算符就学习完了,稍微总结一下

1.基本赋值运算符:
	=符号含义: 把右边的值赋值给左边的变量
	
2.扩展赋值运算符:
	+= -= *= /= %=符号含义:将右边的数据和左边的变量相加、相减、相乘、相除、取余数后,将结果重新赋值给左边的变量。

4.4 关系运算符

接下来我们学习一个,在实际代码中用得很多,但是又非常简单的运算符,叫关系运算符。关系运算符(也叫比较运算符)。

下图是每一种关系运算符的符号及作用,每一个关系运算符的结果都是false

下面通过代码来家演示一下,各种关系运算符的效果

public class OperatorDemo4 {
    public static void main(String[] args) {
        // 目标:掌握关系运算符的基本使用。
        int a = 10;
        int b = 5;
        boolean rs = a > b;
        System.out.println(rs);

        System.out.println(a >= b); // 要么a大于b,或者a等于b
        System.out.println(2 >= 2); // true
        System.out.println(a < b);
        System.out.println(a <= b); // false
        System.out.println(2 <= 2); // true
        System.out.println(a == b); // false
        System.out.println(5 == 5); // true
        
        // 注意了:判断是否相等一定是用 == ,=是用来赋值的。
        // System.out.println(a = b); 
        System.out.println(a != b); // true
        System.out.println(10 != 10); // false

        System.out.println(false ^ true ^ false);
    }
}

现在我们只需要知道每一种关系运算符的运算效果就行了,关于关系运算符的实际运用需要在后面学习了流程控制语句才能实际用到。

关系运算符在程序中常用于条件判断,根据条件判断的结果是true还是false,来决定后续该执行哪些操作。

4.5 逻辑运算符

学习完关系运算符之后,接下来我们学习一下逻辑运算符。我们来看一下逻辑运算符有哪些。

逻辑运算符是用来将多个条件放在一起运算,最终结果是true或者false

下面我们通过几个案例来演示一下逻辑运算符的使用

//需求1:要求手机必须满足尺寸大于等于6.95,且内存必须大于等于8.
//需求2:要求手机要么满足尺寸大于等于6.95,要么内存必须大于等于8.
public class OperatorDemo5 {
    public static void main(String[] args) {
        // 目标:掌握逻辑运算符的使用。
        // 需求:要求手机必须满足尺寸大于等于6.95,且内存必须大于等于8.
        double size = 6.8;
        int storage = 16;
        // 1、& 前后的条件的结果必须都是true ,结果才是true.
        boolean rs = size >= 6.95 & storage >= 8;
        System.out.println(rs);

        // 需求2:要求手机要么满足尺寸大于等于6.95,要么内存必须大于等于8.
        // 2、| 只要多个条件中有一个是true,结果就是true.
        boolean rs2 = size >= 6.95 | storage >= 8;
        System.out.println(rs2);

        // 3、!取反的意思
        System.out.println(!true); // false
        System.out.println(!false); // true
        System.out.println(!(2 > 1)); // false

        // 4、^ 前后条件的结果相同时返回false,不同时返回true.
        System.out.println(true ^ true); // false
        System.out.println(false ^ false); // false
        System.out.println(true ^ false); // true
        System.out.println(false ^ true); // true

        // 5、&& 左边为false,右边不执行。
        int i = 10;
        int j = 20;
        // System.out.println(i > 100 && ++j > 99);
        System.out.println(i > 100 & ++j > 99);
        System.out.println(j);

        // 6、|| 左边是true ,右边就不执行。
        int m = 10;
        int n = 30;
        // System.out.println(m > 3 || ++n > 40);
        System.out.println(m > 3 | ++n > 40);
        System.out.println(n);
    }
}

到这里关于逻辑运算符的规则记学习完了,给你一个运算表达式你能分析出结果就行。至于逻辑运算符的实际运用,需要在学习了流程控制语句之后,才能实际用到。

逻辑运算符在程序中常用于组合几个条件判断,根据条件判断的结果是true还是false,来决定后续该执行哪些操作。

4.6 三元运算符

接下来,我们学习今天最后一种运算符,叫做三元运算符。

先认识一下三元运算符的格式:

关系表达式?1 :2;

三元运算的执行流程:首先计算关系表达式的值,如果关系表达式的值为true,则返回值1;如果关系表达式的值为false, 则返回值2;

判断学生的成绩是否>=60,如果为true,就考试通过;如果为false,就成绩不合格

接下来通过代码来演示一下,目的是让大家掌握三元运算符的格式和执行流程。

public class OperatorDemo6 {
    public static void main(String[] args) {
        // 目标:掌握三元运算符的基本使用。
        double score = 58.5;
        String rs = score >= 60 ? "成绩及格" : "成绩不及格";
        System.out.println(rs);

        // 需求2:找出2个整数中的较大值,并输出。
        int a = 99;
        int b = 69;
        int max = a > b ? a : b;
        System.out.println(max);

        // 需求3:找3个整数中的较大值。
        int i = 10;
        int j = 45;
        int k = 34;

        // 找出2个整数中的较大值。
        int temp = i > j ? i : j;
        // 找出temp与k中的较大值。
        int max2 = temp > k ? temp : k;
        System.out.println(max2);
    }
}

4.7 运算优先级

最后我们在给大家介绍一下运算符的优先级,&&运算比||运算的优先级高,所以&&和||同时存在时,是先算&&再算||;

比如下面的代码

//这里&&先算 相当于 true || false 结果为true
System.out.println(10 > 3 || 10 > 3 && 10 < 3); // true

最后给大家说一下,在实际开发中,其实我们很少考虑运算优先级, 因为如果你想让某些数据先运算,其实加()就可以了,这样阅读性更高。

//有括号先算 相当于 true && false 结果为false
System.out.println((10 > 3 || 10 > 3) && 10 < 3); //false

5.分支结构

5.1 if分支

接下来我们学习分支结构的第一种形式——if分支。

if它的作用,是用于对条件进行判断,判断的结果只可能有两个值true或者false,然后根据条件判断的结果来决定执行那段代码。

接下来我们用一些实际案例给大家演示一下if语句的应用,以及每一种if语句的执行流程。

if 第一种形式

if 第一种形式执行流程如下:
    如果 条件表达式 为true,就执行下面的语句体
    如果 条件表达式 为false,就不执行
// 需求:测量用户体温,发现体温高于37度就报警。
double t = 36.9;
if(t > 37){
    System.out.println("这个人的温度异常,把他赶紧带走~~");
}

if 第二种形式

if 第二种形式执行流程如下:
    如果 条件表达式 为true,就执行下面的语句体1
    如果 条件表达式 为false,就执行else下面的语句体2
// 需求2:发红包,你的钱包余额是99元,现在要发出90元
// 如果钱够触发发红包的动作,如果钱不够,则提示:余额不足。
double money = 19;
if(money >= 90){
    System.out.println("发红包成功了~");
}else {
    System.out.println("余额不足~~");
}

** if 第三种形式**

if 第三种形式执行流程如下:
    如果 条件表达式1true,就执行下面的代码1; 
    如果 条件表达式1false,就继续判断条件表达式2;

    如果 条件表达式2true,就执行下面的语句体;
    如果 条件表达式2false,就继续判断条件语句体3;

    如果 条件表达式3true,就执行下面的语句体3
    如果 条件表达式3false,就继续判断后面的表达式;

    ....
    如果前面所有条件表达式判断都为false,就执行最后的else语句中的代码
// 需求3:某个公司有一个绩效系统,根据员工的打分输出对应的绩效级别。[0,60) D  [60,80) C [80,90) B [90,100] A
int score = 298;
if(score >= 0 && score < 60) {
    System.out.println("您的绩效级别是: D");
}else if(score >= 60 && score < 80){
    System.out.println("您的绩效级别是: C");
}else if(score >= 80 && score < 90){
    System.out.println("您的绩效级别是: B");
}else if(score >= 90 && score <= 100){
    System.out.println("您的绩效级别是: A");
}else {
    System.out.println("您录入的分数有毛病~~");
}

6. if 使用的几个常见问题

同学们在第一次写if 代码时,经常一不小心会出现一些问题。下面把可能出现的问题给大家看一看,以后大家要避免出现这些问题。

  • 第1个问题:if的()后面不能写分号; 否则if下面的语句与if无关
  • 第2个问题:if后面的大括号,如果只有一行代码,大括号可以省略

if 分支小结
关于if分支结构的几种格式,以及各种格式的执行流程,还有if在什么场景下使用我们就讲完了。下面我们总结一下

  • if分支有什么作用?举几个应用场景?
- if作用:if分支可以根据条件,选择执行某段程序
- if应用场景
    比如1:测量用户体温,发现体温高于37度就报警
    比如2:发红包,你的钱包余额是99元,现在要发出90元
    比如3:根据员工的绩效打分输出对应的绩效级别

5.2 switch分支

学完if 分支之后,接下来我们来学习分支结构的第二种形式——switch分支。

1. switch分支的执行流程

switch 分支的作用,是通过比较值来决定执行哪条分支代码
下面通过案例来演示一下

/*
需求:做个电子备忘录,在控制台分别输出周一到周五的工作安排
    周一:埋头苦干,解决bug              
    周二:	请求大牛程序员帮忙             
    周三:今晚啤酒、龙虾、小烧烤      
    周四:主动帮助新来的女程序解决bug
    周五:今晚吃鸡
    周六:与王婆介绍的小芳相亲
    周日:郁郁寡欢、准备上班。
*/
String week = "周三";
switch (week){
    case "周一":
        System.out.println("埋头苦干,解决bug");
        break;
    case "周二":
        System.out.println("请求大牛程序员帮忙");
        break;
    case "周三":
        System.out.println("今晚啤酒、龙虾、小烧烤");
        break;
    case "周四":
        System.out.println("主动帮助新来的女程序解决bug");
        break;
    case "周五":
        System.out.println("今晚吃鸡");
        break;
    case "周六":
        System.out.println("与王婆介绍的小芳相亲");
        break;
    case "周日":
        System.out.println("郁郁寡欢、准备上班");
        break;
    default:
        System.out.println("您输入的星期信息不存在~~~");
}

if 、switch如何选择

学习完switch 分支之后,有同学可能会想,已经了有if分支,为什么还有switch分支呢?感觉上面的案例用if分支也能做啊? 那我们在具体应用场景下如何选择呢?

如果单从功能上来讲,if 分支 的功能是更加强大的,switch分支能做的事情if 分支都能做。但是具体用哪一种分支形式,也是有一些使用原则的

- 如果是对一个范围进行判断,建议使用if分支结构
- 如果是与一个一个的值比较的时候,建议使用switch分支结构

5.3 switch 注意事项

各位同学,接下来我们学习swtich的注意事项。同学们掌握这些注意事项之后,就可以避免入坑了,也可以应对一些面试笔试题。

- 1.表达式类型只能是byteshortintchar
	JDK5开始支持枚举,JDK7开始支持String
	不支持doublefloatdouble
    
- 2.case给出的值不允许重复,且只能是字面量,不能是变量。
		
- 3.正常使用switch的时候,不要忘记写break,否则会出现穿透现象。

6.循环结构

接下来我们学习循环结构。循环结构可以控制一段代码重复执行。循环结构有for循环、while循环、do-while循环。

6.1 for循环——格式和流程

这里首先来学习for循环,同学们重点掌握for循环的书写格式,并理解for循环的执行流程。

1. for循环的格式和流程

为了让大家更直观的理解for循环的执行流程,我们直接来看具体的案例代码。

比如:我们想要在控制台打印输出3个HelloWorld

//需求:打印3行Hello World
for(int i = 0; i < 3; i++) {
    System.out.println("Hello World");
}

通过上面的案例演示,最后我们再总结一下for循环的格式

//for循环格式:
for (初始化语句; 循环条件; 迭代语句) {
    循环体语句(重复执行的代码);
}

初始化语句:一般是定义一个变量,并给初始值
循环条件:一般是一个关系表达式,结果必须是true或者false
迭代语句:用于对条件进行控制,一般是自增或者自减
循环语句体:需要重复执行的代码

** for循环有哪些应用场景**

通过上面的学习,我们已经知道了for循环怎么编写,并且也知道了它的执行流程。

那么具体在哪些实际场景下使用呢?其实只要是重复做的事情,都可以用循环语句来做

6.2 for循环案例1——求和

学完for循环的格式和流程之后,我们再通过案例来巩固一下。通过这个案例,主要是让同学们掌握一种使用程序来求和的思想。

//1.掌握使用for循环批量产生数据。
for (int i = 1; i <= 100; i++) {
    System.out.println(i);
}
求和的思路分析:
	1)首先需要定义一个求和变量,一般命名为sum
	2)再遍历得到所有需要求和的数据(1~100之间的所有整数)
	3)让需要求和的数据和sum累加,
	结果:所有数据累加完之后最终sum就是所有数据的和
//2.需求:求1~100中所有整数的和
int sum = 0;
//定义一个循环,先产生1-100,这100个数
for (int i = 1; i <= 100; i++) {
    //每产生一个数据,就把这个数和sum累加
    sum += i; //sum = sum  + i;
}
System.out.println("1-100的数据和:" +  sum);

分析上面代码的执行过程:

i=1时:sum=0+1; sum=1;
i=2时:sum=1+2; sum=3;
i=3时:sum=3+3; sum=6;
i=4时:sum=6+4; sum=10;
...
i=100: sum+=99; sum=5050

6.3 for循环案例2——求奇数和

需求:求1~100之间奇数的和

1. 代码写法一

求奇数和的思路(只是求和的数据变成了奇数,思路和前面没有变化)
	1)首先需要定义一个求和变量,这里命名为sum1
	2)再遍历得到所有需要求和的数据(1~100之间的所有奇数)
	3)让需要求和的数据和sum1累加,
	结果:所有数据累加完之后最终sum1就是所有数据的和
//1)定义一个变量用于求和
int sum1 = 0;
//2)定义一个循环产生1-100之间的奇数
for (int i = 1; i < 100; i+=2) {
    // i = 1 3 5 7 ...
    //3)让需要求和的数据和sum1累加,
    sum1 += i;
}
System.out.println("1-100之间的奇数和:" +  sum1);

以上代码的执行流程分析

初始化sum1=0;

当i=1时:sum1+=1; sum1=1;
当i=3时:sum1+=3; sum1=4;
当i=5时:sum1+=5; sum1=9;
...
当i=99时:sum1+=99; sum1=2500

2. 代码写法二

求奇数和的思路(只是求和的数据变成了奇数,思路和前面没有变化)
	1)首先需要定义一个求和变量,这里命名为sum2
	2)再遍历得到所有需要求和的数据(1~100之间的所有整数)
	3)在求和之前先对数据判断,如果是奇数,才和sum1累加;否则什么也不干
	结果:所有数据累加完之后最终sum1就是所有数据的和
//1)首先需要定义一个求和变量,这里命名为sum2
int sum2 = 0; 
//2)再遍历得到所有需要求和的数据(1~100之间的所有整数)
for (int i = 1; i <= 100; i++) {
    //i = 1 2 3 4 5 6 ... 99 100
    //3)在求和之前先对数据判断,如果是奇数,才和sum1累加;否则什么也不干
    if(i % 2 == 1){
        // i = 1 3 5 7 9 ... 99
        sum2 += i;
    }
}
System.out.println("1-100之间的奇数和:" + sum2);

for循环小结

今天关于for循环,我们学习这几个案例就够了,重点还是掌握for循环的执行流程。在以后,我们还会经常用到for循环,用多了,你就会越来越熟悉了。但是在具体场景下,还是需要具体问题具体分析。


6.4 while循环——格式和流程

接下来我们学习第二种循环结构——while循环。

// 需求:打印5行Hello World
int i = 0;
while (i < 5) {
    // i = 0 1 2 3 4
    System.out.println("Hello World");
    i++;
}

for、while如何选择

学到这里,细心的同学可能会发现while循环和for循环的执行流程是一样的。那他们是不是可以通用呢?

  • 从功能来说:能够用for循环做的,都能用while循环做。

  • 使用规范上来说:知道循环几次,建议使用for;不知道循环几次建议使用while

6.5 while循环案例——折纸案例

各位同学,上一节我们已经学习了while循环的基本使用。下面我们通过一个案例再将while循环的使用巩固一下,主要目的还是想让大家知道什么使用while循环来完成需求。

案例需求如下:

需求:世界最高山峰珠穆朗玛峰高度是:8848.86=8848860毫米,假如我有一张足够大的它的厚度是0.1毫米。请问:该纸张折叠多少次,可以折成珠穆朗玛峰的高度?

我们来分析一下该怎么做

分析:首先由于不知道折叠多少次,我们可以选择用while循环
	1)纸张的初始化厚度为0.1毫米,珠峰的高度为8848860毫米
		double peakHeight = 8848860;
		double paperThickness = 0.1;
	2)每次折叠纸张的厚度为原来的两倍,这是需要循环执行的
		while(纸张厚度<8848860){
			纸张厚度*=2;
		}
	3)需要求折叠的次数,可以用一个变量来记录折叠的次数
		int 次数 = 0;
		while(纸张厚度<8848860){
			纸张厚度*=2;
            次数++; //每次折叠次数累加
		}
	结果:等循环结束之后,打印记录次数的值,就是折叠多少次了。

按照上面分析的思路把代码写出来

// 1、定义变量记住珠穆朗玛峰的高度和纸张的高度。
double peakHeight = 8848860;
double paperThickness = 0.1;

// 3、定义一个变量count用于记住纸张折叠了多少次
int count = 0;

// 2、定义while循环控制纸张开始折叠
while (paperThickness < peakHeight) {
    // 把纸张进行折叠,把纸张的厚度变成原来的2倍。
    paperThickness = paperThickness * 2;
    count++;
}
System.out.println("需要折叠多少次:" + count);
System.out.println("最终纸张的厚度是:" + paperThickness);

6.6 do-while循环——格式和流程

各位同学,接下来我们学习循环结构的第三种格式——do-while循环。

我们把三种循环的区别给同学们总结一下

1. for循环 和 while循环(先判断后执行); 
   do...while (先执行后判断)
   
2.for循环和while循环的执行流程是一模一样的,
	功能上无区别,for能做的while也能做,反之亦然。
	如果已知循环次数建议使用for循环,如果不清楚要循环多少次建议使用while循环。
	
3 for循环中控制循环的变量只在循环中使用
  while循环中,控制循环的变量在循环后还可以继续使用

6.6 死循环

同学们在写代码时,可能一不小心把代码写成了死循环,所谓死循环就是停不下来的循环。

接下来,带着同学们认识几种死循环的写法。然后再说一下死循环有什么用。

//for死循环
for ( ; ; ){
    System.out.println("Hello World1");
}

//while死循环
while (true) {
    System.out.println("Hello World2");
}

//do-while死循环
do {
    System.out.println("Hello World3");
}while (true);

死循环有什么应用场景呢?

最典型的是可以用死循环来做服务器程序, 比如百度的服务器程序就是一直在执行的,你随时都可以通过浏览器去访问百度。如果哪一天百度的服务器停止了运行,有就意味着所有的人都永不了百度提供的服务了。

对于这样的应用我们目前了解一下就可以了。对于目前来说我们只要知道代码格式该怎么写,能达到什么效果就行。

6.7 循环嵌套

各位同学,接下来我们学习一种在实际工作中很常用的循环形式——循环嵌套。

所谓循环嵌套,就是一个循环中又包含另一个循环(就是常说的,套娃_),下面我们通过案例代码演示一下。

循环嵌套执行流程:外部循环每循环一次,内部循环会全部执行完一轮。

i=0; i<3true; 进入循环
	//j的取值从0到5,执行一轮,打印5次"我爱你"
	for(int j = 1; j <= 5; j++) {
       System.out.println("我爱你:" + i);
    }
    内层循环执行完之后,执行外层的i++; i的值1
    
i=1时:i<3true; 进入循环
	//j的取值从0到5,又执行一轮,打印5次"我爱你"
	for(int j = 1; j <= 5; j++) {
       System.out.println("我爱你:" + i);
    }
    内层循环执行完之后,执行外层的i++; i的值2
    
i=2时:i<3true; 进入循环
	//j的取值从0到5,再执行一轮,打印5次"我爱你"
	for(int j = 1; j <= 5; j++) {
       System.out.println("我爱你:" + i);
    }
    内层循环执行完之后,执行外层的i++; i的值3
    
i=3时:i<3false; 外层循环结束

理解问循环嵌套的执行流程之后,我们再写一个案例来巩固一下

需求:在控制台使用 * 打印出45列的矩形
    ****
    ****
    ****
    ****
//1)先写一个循环用来在一行中打印5个"*"
for (int j = 1; j <= 5; j++) {
    System.out.print("*"); // 不换行
}
System.out.println(); //换行


System.out.println("-----------------");

//2)再将第一步的代码套一层循环,执行4次,就可以打印4行
for (int i = 1; i <= 4; i++) {
    for (int j = 1; j <= 5; j++) {
        System.out.print("*"); // 不换行
    }
    System.out.println(); //换行
}

总结一下,对于嵌套循环重点理解这句话:外部循环每循环一次,内部循环会全部执行完一轮。

6.8 跳转语句 break 、continue

前面我们学习了循环结构,在中间我们还接触了死循环的一些形式,那么我想要在循环过程中提前跳出循环怎么做呢?

这里就需要用到跳转语句,需要用到breakcontinue两个关键字。我们先来认识一下这两个关键字的作用

  • break作用:跳出并结束当前所在循环的执行
  • continue作用:结束本次循环,进入下一次循环

案例1:演示break的使用,提前终止循环的执行

// 1、break:跳出并结束当前所在循环的执行。
// 场景:假如你又有老婆了,你犯错了,你老婆罚你说:5句我爱你
// 说到第三句的时候心软了,让你别再说了。
for (int i = 1; i <= 5; i++) {
    System.out.println("我爱你:" + i);
    if(i == 3){
        // 说明已经说完了第三句了,心软了。
        break; // 跳出并结束当前所在循环的执行。
    }
}

案例2:演示continue的使用,结束循环中的一次,继续下一次循环

// 2、continue:跳出当前循环的当次执行,直接进入循环的下一次执行。
// 场景: 假如你有老婆,你犯错了,你老婆罚你洗碗5天。
// 第三天的时候,你表现很好,第三天不用洗碗,但是不解恨,第四天还是要继续的。
for (int i = 1; i <= 5; i++) {
    if(i == 3) {
        // 已经到了第三天,第三天不用洗的。
        continue;
    }
    System.out.println("洗碗:" + i);
}

6.9 循环结构总结

到这里关于循环结构的所有内容就都已经学习完了,我们再把几种循环结构在什么场景下使用,再总结一下。

1. 什么是流程控制
	答:流程控制是用来控制程序的执行顺序的
	
2. 分支结构ifswitch,如何选择?
	答:if分支:一般用于对一个范围进行判断
		switch分支:对一个一个值进行匹配
		
3. for循环和while循环、do-while如何循环
	答:知道循环次数用for、不知道循环次数用while
	   想要先执行,再判断,用do-while

7.生成随机数

接下来我们再学习一个新的知识——生成随机数。

生成随机数其实在很多场景下都很实用,比如,在课堂上可以写一个随机点名器点同学起来回答问题;再比如公司年会可以随机抽奖等。

7.1 如何产生一个随机数

生成随机数的功能,其实 Java已经给我们提供了,在JDK中提供了一个类叫做Random,我们只需要调用Random这个类提供的功能就可以了。

// 目标:掌握使用Random生成随机数的步骤。
// 1、导包。import java.util.Random; (idea会自动完成)
import java.util.Random;
public class RandomDemo1 {
    public static void main(String[] args) {
        // 2、创建一个Random对象,用于生成随机数。
        Random r = new Random();
        // 3、调用Random提供的功能:nextInt得到随机数。
        for (int i = 1; i <= 20; i++) {
            int data = r.nextInt(10); // 0 - 9
            System.out.println(data);
        }
    }
}

7.2 猜数字小游戏

各位同学,接下来我们通过一个案例把前面的流程控制、跳转语句、随机数综合运用一下;

如果能把这个案例写出来,说明你对今天的知识点掌握得挺好了。

需求:
	随机生成一个1-100之间的数据,提示用户猜测,猜大提示过大,猜小提示过小,直到猜中	  结束游戏

分析:
	1.先随机生成一个1-100之间的数据。
		谁可以帮你生成随机数啊? 是不是要用到Random2.定义一个死循环让用户可以一直猜测。
		用户猜的数据从哪里来啊? 是不是要用到Scanner?

	3.在死循环里,每次让用户录入的数据和随机数进行比较
		如果比随机数大:提示猜大了
		如果比随机数小:提示猜小了
		如果和随机数相同:提示恭喜你猜中了
import java.util.Random;
import java.util.Scanner;

public class RandomTest2 {
    public static void main(String[] args) {
        // 1、随机产生一个1-100之间的数据,做为中奖号码。
        Random r = new Random();
        int luckNumber = r.nextInt(100) + 1;

        // 2、定义一个死循环,让用户不断的猜测数据
        Scanner sc = new Scanner(System.in);
        while (true) {
            // 提示用户猜测
            System.out.println("请您输入您猜测的数据:");
            int guessNumber = sc.nextInt();

            // 3、判断用户猜测的数字与幸运号码的大小情况
            if(guessNumber > luckNumber){
                System.out.println("您猜测的数字过大~~");
            }else if(guessNumber < luckNumber){
                System.out.println("您猜测的数字过小~~");
            }else {
                System.out.println("恭喜您,猜测成功了,可以买单了~~");
                break; // 结束死循环
            }
        }
    }
}

8.认识数组

先来认识一下什么数组

8.1. 什么数组

数组就是一个容器,用来存一批同种类型的数据的。

比如:想要存储 20,10,80,60,90 这些数据。 我们可以把代码写成这样

int[] array = {20,10,80,60,90};

比如:想要存储 “牛二“,“西门“,“全蛋“ 这些数据。我们可以把代码写成这样

String[] names = {"牛二", "西门", "全蛋"};

8.2. 数组的应用场景

有变量,为什么还要有数组呢? 比如,我们要做一个点名器
遇到批量数据的存储和操作时,数组比变量更适合

9.数组的定义和访问

我们已经知道数组是用来干什么的。那么如何使用Java语言写一个数组呢?这里就需要学习一下数组的初始化格式。

数组有两种初始化的方式,一种是静态初始化、一种是动态初始化。我们先用静态初始化来学习数组的操作。

9.1 数组的静态初始化

所谓静态初始化指的是:在定义数组时直接给数组中的数据赋值。

1. 静态初始化标准格式:

数据类型[] 变量名 = new 数据类型[]{元素1,元素2,元素3};

按照格式定义int类型、double类型数组

//定义数组,用来存储多个年龄
int[] ages = new int[]{12, 24, 36}
//定义数组,用来存储多个成绩
double[] scores = new double[]{89.9, 99.5, 59.5, 88.0};

2. 静态初始化简化格式

Java语言的设计者为了简化定义数组的写法,还为静态初始化提供了一种简化写法

数据类型[] 变量名 = {元素1,元素2,元素3};

使用简化格式定义int类型、double类型数组

//定义数组,用来存储多个年龄
int[] ages = {12, 24, 36}
//定义数组,用来存储多个成绩
double[] scores = {89.9, 99.5, 59.5, 88.0};

3. 注意哟!!

  • 定义数组时, 数据类型[] 数组名 也可写成 数据类型 数组名[]
//以下两种写法是等价的。但是建议大家用第一种,因为这种写法更加普遍
int[] ages = {12, 24, 36};
int ages[] = {12, 24, 36}

4. 数组在计算机中的基本原理

我们知道数组是怎么定义的之后,那么接下来看一下数组在计算机中的基本原理。

我们以int[] ages = {12,24,36};这句话为例,看一下这句话到底在计算机中做了那些事情。

  • 首先,左边int[] ages 表示定义了一个数组类型的变量,变量名叫ages
  • 其次,右边{12,24,36}表示创建一个数组对象,你完全可以把它理解成一个能装数据的东西。这个对象在内存中会有一个地址值[I@4c873330,每次创建一个数组对象都会有不用的地址值。
  • 然后,把右边的地址值[I@4c873330赋值给左边的ages变量
  • 所以,ages变量就可以通过地址值,找到数组这个东西。

9.2 数组的元素访问

各位同学,通过刚才的学习,我们知道数组是用来存储数据的。那么数组中存储的数据又如何访问呢?这里所说的访问,意思就是获取中数组中数据的值、或者给数组中的数据赋值。

这里先给大家统一几个概念,数组中存储的数据我们叫做元素;而且数组中的每一个元素都有一个编号与之对应,我们把这个编号叫做索引,这个索引是从0依次递增的整数。

要想访问数组中的元素,格式如下

//数组名可以找到数组对象的地址,再通过索引就可以定位到具体的元素了
数组名[索引]

接下来用代码来演示一下

//索引:	   0   1   2
int[] arr = {12, 24, 36};
// 1、访问数组的全部数据
System.out.println(arr[0]); //12
System.out.println(arr[1]); //24
System.out.println(arr[2]); //36
//下面代码没有3索引,会出现ArrayIndexOutOfBoundsException 索引越界异常
//System.out.println(arr[3]); 

// 2、修改数组中的数据
arr[0] = 66;
arr[2] = 100;
System.out.println(arr[0]); //66
System.out.println(arr[1]); 0
System.out.println(arr[2]); //100

除了访问数组中的元素,我们可以获取数组中元素的个数,后面我们统称为数组的长度。

// 3、访问数组的元素个数:数组名.length
System.out.println(arr.length);

// 技巧:获取数组的最大索引: arr.length - 1(前提是数组中存在数据)
System.out.println(arr.length - 1);

int[] arr2 = {};
System.out.println(arr2.length - 1);

9.3 数组的遍历

接下来我们学习一个对数组最最最常见的操作——数组遍历。所谓遍历意思就是将数组中的元素一个一个的取出来。

我们刚才学习了数组中元素的访问,访问元素必须用到索引,如下列代码。

int[] ages = {12, 24, 36};
System.out.println(ages[0]);
System.out.println(ages[1]);
System.out.println(ages[2]);

但是,如果数组中有很多很多元素,索引靠自己一个一个数肯定是不行的!我们可以使用for循环从0开始一直遍历到长度-1的位置,就可以获取所有的索引了。

当你获取到每一个索引,那么每一个元素不就获取到了吗?上代码吧

int[] ages = {12, 24, 36};
for (int i = 0; i < ages.length; i++) {
    // i的取值 = 0,1,2
    System.out.println(ages[i]); 
}

9.4 数组静态初始化案例

学习完数组的静态初始化之后,接下来我们做一个练习题来巩固一下。

需求:某部门5名员工的销售额分别是:1626366100,请计算出他们部门的总销售额。

需求分析:
	1.看到有16263661005个数据数据,而且数据值很明确;
		1)想到,可以使用数组静态初始化把这5个数据存起来
	
	2.请计算出他们部门的总销售额(这不就是求数组中数据的和吗?)
		2)必须先将数组中所有的元素遍历出来
		3)想要求和,得先有一个求和变量sum
		4)再将每一个元素和求和变量sum进行累加(求和思想)

按照分析的思路来写代码

// 1、定义一个数组存储5名员工的销售额
//索引          0   1    2  3   4
int[] money = {16, 26, 36, 6, 100};

// 3、定义一个变量用于累加求和
int sum = 0;

// 2、遍历这个数组中的每个数据。
for (int i = 0; i < money.length; i++) {
    // i = 0  1  2  3  4
    sum += money[i];
}
System.out.println("员工的销售总额:" + sum);

9.5 数组的动态初始化

各位同学,刚才我们初始化数组时,都是直接将元素写出来。但是还有另一个初始化数组的方式叫 动态初始化

动态初始化不需要我们写出具体的元素,而是指定元素类型和长度就行。格式如下

//数据类型[]  数组名 = new 数据类型[长度];
int[] arr = new int[3];

下面是动态初始化数组的原理图。我们发现int[] arr 其实就是一个变量,它记录了数组对象的地址值,而且数组中的元素默认值是0。

注意:

使用动态初始化定义数组时,根据元素类型不同,默认值也有所不同。

关于数组动态初始化的格式和原理,咱们就先学习到这里。

9.6 数组动态初始化案例

各位同学,接下来我们做一个数组动态初始化的案例。

案例需求:
	某歌唱比赛,需要开发一个系统:可以录入6名评委的打分,录入完毕后立即输出平均分做
	选手得分

需求分析:
	1.需要录入6名评委的分数,可以用一个数组来保存。
	   因为在评委没有录入分数之前,还不确定数组中应该存哪些数据。
	   所以可以使用数组的动态初始化
	2.遍历数组中的每一个位置,并录入分数,将分数存入数组中
	3.遍历数组中的每一个元素,对元素求和

代码如下

// 1、定义一个动态初始化的数组,负责后期存储6个评委的打分。
double[] scores = new double[6];

Scanner sc  = new Scanner(System.in);

// 2、遍历数组中的每个位置,录入评委的分数,存入到数组中去
for (int i = 0; i < scores.length; i++) {
    // i = 0 1 2 3 4 5
    System.out.println("请您输入当前第" + (i + 1) +"个评委的分数:");
    double score = sc.nextDouble();
    scores[i] = score;
}

// 3、遍历数组中的每个元素进行求和
double sum  = 0;
for (int i = 0; i < scores.length; i++) {
    sum += scores[i];
}
System.out.println("选手最终得分是:" + sum / scores.length);

10.数组在计算机中的执行原理

好的各位同学,在前面我们已经学习了数组的基本使用,也理解了数组的基本原理。由于数组是一个容器,变量也是一个容器,在理解他们执行原理的时候,有些同学就容易搞混,现在我把他们放在一起带着大家回顾一下他们的会执行原理,顺便带着大家详细理解一下Java程序的执行的内存原理。

10.1 数组的执行原理,Java程序的执行原理

我们以下面的代码,来讲解变量、数组的执原理。

public class ArrayDemo1 {
    public static void main(String[] args) {
        int a = 10;
        System.out.println(a);

        int[] arr = new int[]{11, 22, 33};
        System.out.println(arr);

        System.out.println(arr[1]);

        arr[0] = 44;
        arr[1] = 55;
        arr[2] = 66;

        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

前面我们给大家讲过,程序是在内存中执行的。实际上Java程序是把编译后的字节码加载到Java虚拟机中执行的。

Java为了便于虚拟机执行Java程序,将虚拟机的内存划分为 方法区、栈、堆、本地方法栈、寄存器 这5块区域。同学们需要重点关注的是 方法区、栈、堆

下面把每一个块内存区域作用介绍一下,我们大致只需要知道每一部分存储什么内容就行。

  • 方法区:字节码文件先加载到这里
  • :方法运行时所进入的内存区域,由于变量在方法中,所以变量也在这一块区域中
  • :存储new出来的东西,并分配地址。由于数组是new 出来的,所以数组也在这块区域。

总结一下int a = 10int[] arr = new int[]{11,22,33}的区别

  • a是一个变量,在栈内存中,a变量中存储的数据就是10这个值。
  • arr也是一个变量,在栈中,存储的是数组对象在堆内存中的地址值
// 这里的int a是一个基本类型变量,存储的是一个数值
int a = 10 ; 
//这里的int[] arr是一个引用类型的变量,存储的是一个地址值
int[] arr = new int[]{44,55,66};

10.2 多个变量指向同一个数组的问题

各位同学,我们了解了数组在内存中的执行原理。我们知道数组类型的变量,指向的是堆内存中数组对象的地址。但是在实际开发中可能存在一种特殊情况,就是多个变量指向同一个数组对象的形式。

讲解这个知识点的目的,是让同学们注意多个变量指向同一个数组对象存在什么问题?

我们先看一段代码

public class ArrayDemo2 {
    public static void main(String[] args) {
        // 目标:认识多个变量指向同一个数组对象的形式,并掌握其注意事项。
        int[] arr1 = {11, 22, 33};

        // 把int类型的数组变量arr1赋值给int类型的数组变量arr2
        int[] arr2 = arr1;

        System.out.println(arr1);
        System.out.println(arr2);

        arr2[1] = 99;
        System.out.println(arr1[1]);

        arr2 = null; // 拿到的数组变量中存储的值是null
        System.out.println(arr2);

        //System.out.println(arr2[0]);
        //System.out.println(arr2.length);
    }
}

总结一下:

  • 两个变量指向同一个数组时,两个变量记录的是同一个地址值。

  • 当一个变量修改数组中的元素时,另一个变量去访问数组中的元素,元素已经被修改过了。

到这里有关数组的基本操作,和内存原理我们就全部学习完了。

11.数组专项练习

接下来我们做一些专项练习题,把数组的常见操作练习一下。在学习这个案例时,重点掌握数组求最值的思路,代码只是用来表达你的思路的。

11.1 数组求最值

需求:定义一个int类型数组,求数组中元素的最大值,并打印最大值

我们先看一下选美比赛,是怎么选出颜值最高的人的。然后再以此思路,来写代码找出数组中元素的最大值。

数组求最大值思路:
	1)先找出数组中0索引的元素,假设为最大值,用max表示【擂主】
	2)遍历后面的每一个元素和max比较,把较大的元素值重新赋值给max(擂主换人)
    3)最后max就是所有元素的最大值(最后站在台上的擂主)
public class Test1 {
    public static void main(String[] args) {
        // 1、把颜值数据拿到程序中来,用数组装起来
        int[] faceScores = {15, 9000, 10000, 20000, 9500, -5};

        // 2、定义一个变量用于最终记住最大值。
        int max = faceScores[0];

        // 3、从数组的第二个位置开始遍历。
        for (int i = 1; i < faceScores.length; i++) {
            // i = 1  2  3  4  5
            // 判断一下当前遍历的这个数据,是否大于最大值变量max存储的数据,
            //如果大于,当前遍历的数据需要赋值给max
            if(faceScores[i] > max ){
                max = faceScores[i];
            }
        }
        System.out.println("最高颜值是:" + max);
    }
}

总结一下:

通过这个案例,我们主要掌握求最值的思路,以后不管遇到求最大值还是最小值,编程思路都是一样的,不同的可能是数据不同。

11.2 数组元素反转

需求:某个数组有5个数据:10,20,30,40,50,请将这个数组中的数据进行反转。
      [10, 20, 30, 40, 50]  反转后 [50, 40, 30, 20, 10]

数组元素反转的核心,其实是数组中两个数据的交换。我们可以认为两个数据分别存储在两个水杯中。想要交换两个水杯中的东西,我们得借助第三个水杯

数组中元素交换,就是用的借用第三方变量的思想。 我们把数组中的每一个元素当做一个水杯,然后索引控制哪两个元素互换位置。

怎么样,才能达到元素反转的效果呢?我们只需将第一个和最后一个元素互换、第二个和倒数第二个互换、依次内推… 如下图所示

怎么样写代码,才能达到上面的效果呢?我们继续分析

1.每次交换,需要有左右两边的两个索引,我们可以用i和j表示
	刚开始i=0,j=数组长度-1;
2.每次让i和j索引位置的两个元素互换位置
	arr[i]和arr[j]互换位置
3.每次还完位置之后,让i往右移动一位,让j往前移动一位

具体代码如下

public class Test2 {
    public static void main(String[] args) {
        // 目标:完成数组反转。
        // 1、准备一个数组
        int[] arr = {10, 20, 30, 40, 50};  

        // 2、定义一个循环,设计2个变量,一个在前,一个在后
        for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
            // arr[i]   arr[j]
            // 交换
            // 1、定义一个临时变量记住后一个位置处的值
            int temp = arr[j];
            // 2、把前一个位置处的值赋值给后一个位置了
            arr[j] = arr[i];
            // 3、把临时变量中记住的后一个位置处的值赋值给前一个位置处
            arr[i] = temp;
        }

        // 3、遍历数组中的每个数据,看是否反转成功了
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

总结一下:

通过上面的案例,需要我们掌握元素互换位置的编程思路;以后遇到数据互换问题,都这样做。

11.3 随机排名

各位同学,通过数组元素反转的案例,我们学会了如何对两个数据进行交换。接下来,我们再学习随机排名案例,将数据交换的思路再巩固一下。

先来看一下需求

需求:某公司开发部5名开发人员,要进行项目进展汇报演讲,现在采取随机排名后进行汇报。请先依次录入5名员工的工号,然后展示出一组随机的排名顺序。

分析一下随机排名的思路

1.在程序中录入5名员工的工号存储起来 ---> 使用动态初始化数组的方式。
2.依次遍历数组中的每个数据。
3.每遍历到一个数据,都随机一个索引值出来,让当前数据与该索引位置处的数据进行交换。

如下图所示,每次遍历到一个元素,随机将当前位置元素和随机索引元素换位置。

代码如下

public class Test3 {
    public static void main(String[] args) {
        // 目标:完成随机排名
        // 1、定义一个动态初始化的数组用于存储5名员工的工号
        int[] codes = new int[5];

        // 2、提示用户录入5名员工的工号。
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < codes.length; i++) {
            // i = 0 1 2 3 4
            System.out.println("请您输入第" + (i + 1) +"个员工的工号:");
            int code = sc.nextInt();
            codes[i] = code;
        }

        // 3、打乱数组中的元素顺序。
        // [12, 33, 54, 26, 8]
        //  i       index
        Random r =  new Random();
        for (int i = 0; i < codes.length; i++) {
            // codes[i]
            // 每遍历到一个数据,都随机一个数组索引范围内的值。
            //然后让当前遍历的数据与该索引位置处的值交换。
            int index = r.nextInt(codes.length); // 0 - 4
            // 定义一个临时变量记住index位置处的值
            int temp = codes[index];
            // 把i位置处的值赋值给index位置处
            codes[index] = codes[i];
            // 把index位置原来的值赋值给i位置处
            codes[i] = temp;
        }

        // 4、遍历数组中的工号输出即可
        for (int i = 0; i < codes.length; i++) {
            System.out.print(codes[i] + " ");
        }
    }
}

到这有关数组的常见练习题我们就讲完了,待会我们在给同学们讲一个开发中用得比较多的工具叫做Debug调试。

12.Debug调试工具

各位同学,为了让大家更好的理解代码的执行流程,这里给大家讲一个在开发中非常重要的工具——叫做Debug调试。

通过Debug调试,我们可以查看代码的执行流程。当你代码中有Bug但是又发现不了的时候,你就可以用Debug调试工具,查看执行流程,逐步分析是哪一行出现了问题。

Debug调试工具的使用步骤如下:

第一步:打断点,如下图的红色小圆点
第二步:右键Debug方式启动程序,如下图右键菜单
	  启动后,代码会停留在打断点的这一行
第三步:点击箭头按钮,一行一行往下执行

13.方法概述

13.1 方法是什么

**方法是一种语法结构,它可以把一段代码封装成一个功能,以便重复调用。**这句话什么意思呢?意思是,把一段功能代码围在一起,别人都可以来调用它。

我们看一个需求,比如现在张工、李工两个人都需要求两个整数的和。不使用方法,代码如下。

// 1、李工。
int a = 10;
int b = 20;
int c = a+b;
System.out.println("和是:" + c);


// 2、张工。
int a1 = 10;
int b1 = 20;
int c1 = a1+b1;
System.out.println("和是:" + c1);

阅读上面的代码,我们不难发现。两次求和的代码中,除了求和的数据不一样,代码的组织结构完全一样。

像这种做相同事情的代码,就可以用方法进行封装。需要用到这段代码功能时,让别人调用方法就行。代码如下

//目标:掌握定义方法的完整格式,搞清楚使用方法的好处。
public class MethodDemo1 {
    public static void main(String[] args) {
        // 需求:假如现在很多程序员都要进行2个整数求和的操作。
        // 1、李工。
        int rs = sum(10, 20);
        System.out.println("和是:" + rs);

        // 2、张工。
        int rs2 = sum(30, 20);
        System.out.println("和是:" + rs2);
    }

    public static int sum(int a,int b) {
        int c = a + b;
        return c;
    }
}

13.2 方法的执行流程

当调用一个方法时,执行流程,按照下图中标注的序号执行。

​ ① 通过sum方法名找到sum方法

​ ② 把10传递给方法中的参数a

​ ③ 把20传递给方法中的参数b;

​ ④ 执行方法中的代码,此时int c=a+b;; 相当于 int c = 10+20; c的值为30

return c 的含义是,把c的结果返回给调用处。 也就是调用sum方法的结果为30,

学习完方法的执行流程之后,下面有几个注意事项需要我们写代码时注意一下。

13.3 定义方法的注意点

  1. 方法的修饰符:暂时都使用public static 修饰。(目前看做是固定写法,后面是可以改动的)

  2. 方法申明了具体的返回值类型,内部必须使用return返回对应类型的数据。

  3. 形参列表可以有多个,甚至可以没有; 如果有多个形参,多个形参必须用“,”隔开,且不能给初始化值。

13.4 使用方法的好处

最好,我们总结一下,用方法有什么好处,可以归纳为下面2点:

  1. 提高了代码的复用性,提高了开发效率。
  2. 让程序的逻辑更清晰。

如下图所示:写好一个方法之后,每一个人都可以直接调用,而不用再重复写相同的代码。所以是提高了代码的复用性,不用写重复代码,自然也提高了开发效率。

那么让程序的逻辑更加清晰,是如何体现的呢? 比如,我们后期会用所学习的技术,做一个ATM系统,ATM系统中有查看账户、存钱、取钱、修改密码等功能,到时候我们可以把每一个功能都写成一个方法。如下图所示,这样程序的逻辑就更加清晰了。

好了,关于方法是什么,以及方法的基本使用就学习到这里。

总结一下

1.什么是方法?
	答:方法是一种语法结构,它可以把一段代码封装成一个功能,以便重复调用
2.方法的完整格式是什么样的?
	//格式如下:
	修饰符  返回值类型  方法名( 形参列表 ){
    	方法体代码(需要执行的功能代码)
       	return 返回值;
    }
3.方法要执行必须怎么办?
	必须调用才执行; 
	//调用格式:
	方法名(...);

4.使用方法有什么好处?
	答:提高代码的复用性,提高开发效率,使程序逻辑更清晰。

14.方法的其他形式

各位同学,刚才我们学习了定义完整格式的方法。但是实际开发中,需要按照方法解决的实际业务需求,设计出合理的方法形式来解决问题。

设计一个合理的方法的原则如下:

  • 如果方法不需要返回数据,返回值类型必须申明成void(无返回值申明), 此时方法内部不可以使用return返回数据。
  • 方法如果不需要接收外部传递进来的数据,则不需要定义形参,且调用方法时也不可以传数据给方法。
  • 没有参数,且没有返回值类型(void)的方法,称为值无参数、无返回值方法。此时调用方法时不能传递数据给方法。

接下来我们看几个案例代码,练习根据实际需求定义出合理的方法

需求1:写一个方法,打印3个"Hello World"

分析:需求已经非常明确,打印的是3个HelloWorld,在方法中直接循环3次就可以完成需求。不需要外部给方法传递数据,所以不需要参数。

需求2:写一个方法,打印若干个"Hello World",具体多少个,有调用者指定

分析:需求不明确打印HelloWorld的个数,而是需要调用者指定。也就是说,调用者调用方法时需要给方法传递打印HelloWorld的个数。那么定义方法时,就需要写一个参数,来接收调用者传递过来的个数。

15.方法使用常见的问题

各位同学,自己第一次写方法时,或多或少会可能会出现一些问题。下面把使用方法时,常见的问题整理一下。

目的是让同学们,以后写方法时避免出现这些问题。一旦出现这些问题,要知道是什么原因。

- 1. 方法在内种没有先后顺序,但是不能把一个方法定义在另一个方法中。

- 2. 方法的返回值类型写void(无返回申明)时,方法内不能使用return返回数据,
	如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据。

- 3. return语句的下面,不能编写代码,属于无效的代码,执行不到这儿。

- 4. 方法不调用就不会执行,  调用方法时,传给方法的数据,必须严格匹配方法的参数情况。

- 5. 调用有返回值的方法,有3种方式:
     ① 可以定义变量接收结果 
     ② 或者直接输出调用,
     ③ 甚至直接调用;

- 6. 调用无返回值的方法,只有1种方式: 只能直接调用。

16.方法在计算机中的执行原理

各位同学,刚才我们已经写了好几个方法并成功调用了。但是不知道同学们奇不奇怪一个问题。方法在计算机的内存中到底是怎么干的呢?

为了让大家更加深刻的理解方法的执行过程,接下来,给同学们讲一下方法在计算机中的执行原理。理解方法的执行原理,对我们以后知识的学习也是有帮助的。

我们知道Java程序的运行,都是在内存中执行的,而内存区域又分为栈、堆和方法区。那Java的方法是在哪个内存区域中执行呢?

答案是栈内存。 每次调用方法,方法都会进栈执行;执行完后,又会弹栈出去。

方法进栈和弹栈的过程,就类似于手枪子弹夹,上子弹和击发子弹的过程。最后上的一颗子弹是,第一个打出来的;第一颗上的子弹,是最后一个打出来的。

假设在main方法中依次调用A方法、B方法、C方法,在内存中的执行流程如下:

  • 每次调用方法,方法都会从栈顶压栈执行没执行
  • 每个方法执行完后,会从栈顶弹栈出去

16.1 有返回值的方法,内存分析

下面我们分析一下,求两个整数和的代码,在内存中的执行原理。

public class MethodDemo {
    public static void main(String[] args) {
        int rs = sum(10, 20);
        System.out.println(rs);
	}
    public static int sum(int a, int b ){
        int c = a + b; 
        return c;  
    }
}

16.2 无返回值的方法,内存分析

刚才我们分析的是有有参数有返回值的方法内存原理。下面再分析一个无返回值、无参数的内存原理。

public class Demo2Method {
    public static void main(String[] args) {
        study();
    }

    public static void study(){
		eat();
		System.out.println("学习");
		sleep();
	}
    public static void eat(){
        System.out.println("吃饭");
    }
    
    public static void sleep(){
        System.out.println("睡觉");
    }
}

总结一下

1.方法的运行区域在哪里?
	答:栈内存。
	
2.栈有什么特点?方法为什么要在栈中运行自己?
	答:先进后出。保证一个方法调用完另一个方法后,可以回来继续执行。

17.方法参数的传递机制

各位同学,刚才我们学习了方法运行的原理,相信大家对方法的运行过程有更加深刻的认识。但是方法参数的传递过程还需要,还需要进一步学习一下。

因为我们刚才演示的一些方法中传递的参数都是基本类型,实际上参数还可以是传递引用类型。接下来,学习一下当参数是基本类型时、和参数是引用类型时的区别。

先记住一个结论:Java的参数传递机制都是:值传递

所谓值传递:指的是在传递实参给方法的形参的时候,传递的是实参变量中存储的值的副本。 同学们肯定想知道,形参是什么?实参又是什么呢?

17.1 参数传递的基本类型数据

接下来,看一下方法参数传递是基本类型数据时,内存中是怎么执行的。

我们把参数传递的结论再复习一下:Java的参数传递机制都是:值传递,传递的是实参存储的值的副本。

17.2 参数传递的是引用数据类型

接下来,看一下方法的参数是引用类型的数据时,内存中是怎么执行的。

我们发现调用change方法时参数是引用类型,实际上也是值传递,只不过参数传递存储的地址值。此时change方法和main方法中两个方法中各自有一个变量arrs,这两个变量记录的是同一个地址值4c873330,change方法把数组中的元素改了,main方法在访问时,元素已经被修改了。

总结一下:

1.基本类型和引用类型的参数在传递的时候有什么不同?
	= 都是值传递
	- 基本类型的参数传递存储的数据值。
    - 引用类型的参数传递存储的地址值。

18.方法参数传递案例

18.1 方法参数传递案例1

需求:输出一个int类型的数组内容,要求输出格式为:[11, 22, 33, 44, 55]。

分析:
	 1.方法是否需要接收数据进行处理?
	 	方法要打印int类型数组中的元素,打印哪一个数组需求并不明确;
        所以可以把int数组写成参数,让调用者指定
        
	 2.方法是否需要返回数据?
	 	方法最终的目的知识打印数组中的元素。
	 	不需要给调用者返回什么,所以不需要返回值,返回值类型写void
	 
	 3.方法内部的业务:遍历数组,并输出相应的内容

代码如下

public class MethodTest3 {
    public static void main(String[] args) {
        // 目标:完成打印int类型的数组内容。
        int[] arr = {10, 30, 50, 70};
        printArray(arr);

        int[] arr2 = null;
        printArray(arr2);

        int[] arr3 = {};
        printArray(arr3);
    }

    /*
    	参数:int[] arr表示要被打印元素的数组,需要调用者传递
    */
    public static void printArray(int[] arr){
        if(arr == null){
            System.out.println(arr); // null
            return; // 跳出当前方法
        }

        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("]");
    }
}

18.2 方法参数传递案例2

需求:比较两个int类型的数组是否一样,返回true或者false

分析:
	1.方法是否需要接收数据进行处理?
		因为,方法中需要两个int数组比较,但是需求并不明确是哪两个数组;
		所以,需要接收两个int类型的数组,形参声明为:int[] arr1,int[] arr2 

 	2.方法是否需要返回数据?
 		因为,方法最终的结果需要true或者false;
		所以,返回值类型是boolean
 		
	3. 方法内部的业务:判断两个数组内容是否一样。

代码如下

public class MethodTest4 {
    public static void main(String[] args) {
        // 目标:完成判断两个int类型的数组是否一样。
        int[] arr1 = {10, 20, 30};
        int[] arr2 = {10, 20, 30};
        System.out.println(equals(arr1, arr2));
    }

    /*
    	参数:
    		int[] arr1, 参与比较的第一个int数组
    		int[] arr2  参与比较的第二个int数组
    	返回值:
    		返回比较的结果true或者false
    */
    public static boolean equals(int[] arr1, int[] arr2){
        // 1、判断arr1和arr2是否都是null.
        if(arr1 == null && arr2 == null){
            return true; // 相等的
        }

        // 2、判断arr1是null,或者arr2是null.
        if(arr1 == null || arr2 == null) {
            return false; // 不相等
        }

        // 3、判断2个数组的长度是否一样,如果长度不一样,直接返回false.
        if(arr1.length != arr2.length){
            return false; // 不相等
        }

        // 4、两个数组的长度是一样的,接着比较它们的内容是否一样。
        // arr1 = [10, 20, 30]
        // arr2 = [10, 20, 30]
        for (int i = 0; i < arr1.length; i++) {
            // 判断当前位置2个数组的元素是否不一样,不一样直接返回false
            if(arr1[i] != arr2[i]){
                return false; // 不相等的
            }
        }
        return true; // 两个数组是一样的。
    }
}

19.方法重载

接下来,我们学习一个开发中很重要的一个方法的形式——叫方法重载。

所谓方法重载指的是:一个类中,出现多个相同的方法名,但是它们的形参列表是不同的,那么这些方法就称为方法重载了。

我们在这里要能够认识,哪些是重载的方法。

下面案例中有多个test方法,但是参数列表都不一样,它们都是重载的方法。调用时只需要通过参数来区分即可。

public class MethodOverLoadDemo1 {
    public static void main(String[] args) {
        // 目标:认识方法重载,并掌握其应用场景。
        test();
        test(100);
    }

    public static void test(){
        System.out.println("===test1===");
    }

    public static void test(int a){
        System.out.println("===test2===" + a);
    }

    void test(double a){

    }

    void test(double a, int b){
    }

    void test(int b, double a){
    }

    int test(int a, int b){
        return a + b;
    }
}

我们认识了方法重载,那么方法重载有哪些应用场景呢?

一般在开发中,我们经常需要为处理一类业务,提供多种解决方案,此时用方法重载来设计是很专业的。

比如,我们现在看一个案例

需求:开发武器系统,功能需求如下:
    可以默认发一枚武器。
    可以指定地区发射一枚武器。
    可以指定地区发射多枚武器。

上面的几个需求中,不管以什么样的方式发武器,其实最终的目的都是发武器。

所以我们可以设计几个名称相同的方法,这样调用者调用起来就不用记那么多名字了

代码如下:

public class MethodTest2 {
    public static void main(String[] args) {
        // 目标:掌握方法重载的应用场景。
        fire();
        fire("岛国2");
        fire("米国", 999);
    }

    public static void fire(){
        fire("岛国");
    }

    public static void fire(String country){
        fire(country, 1);
    }

    public static void fire(String country, int number){
        System.out.println("发射了" + number + "枚武器给" + country);
    }
}

总结一下:

1.什么是方法重载?
	答:一个类中,多个方法的名称相同,但它们形参列表不同。
2.方法重载需要注意什么?
	- 一个类中,只要一些方法的名称相同、形参列表不同,那么它们就是方法重载了,
	  其它的都不管(如:修饰符,返回值类型是否一样都无所谓)。
	
	- 形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。
	
3、方法重载有啥应用场景?
	答:开发中我们经常需要为处理一类业务,提供多种解决方案,此时用方法重载来设计是很	专业的。

20.return单独使用

各位同学,关于方法的定义,我们还剩下最后一种特殊用法,就是在方法中单独使用return语句,可以用来提前结束方法的执行。

如,下面的chu方法中,当除数为0时,就提前结束方法的执行。

public class Test {
    public static void main(String[] args) {
        System.out.println("开始");
        chu(10 , 0);
        System.out.println("结束");
    }
    
    public static void chu(int a , int b){
        if(b == 0){
            System.err.println(“您的数据有误!!不执行!!”);
            return; // 直接跳出并结束当前chu方法的执行
        }
        int c = a / b;
        System.out.println("除法结果是:"+c); 
    }
}
posted @ 2024-08-01 16:39  写代码的大学生  阅读(18)  评论(0编辑  收藏  举报  来源