写在前面:
视频是什么东西,有看文档精彩吗?
视频是什么东西,有看文档速度快吗?
视频是什么东西,有看文档效率高吗?
清晨 06:16,张小飞睡的正香,突然感觉到一股寒意 ,或许是因为第六感的缘故,张小飞警觉的张眸
果然,还迷糊的眼睛,看到了一个人影。张小飞下意识的想要大叫‘好汉饶命,我上有老父,下有妻儿,家穷……’之类的话
而后,这个床边的人毫不犹豫的用手捂住了张小飞的嘴。便听一个熟悉的声音道:“嘘,是我”
卧……卧槽……
张小飞怒了,不怕贼偷就怕贼惦记啊,这家伙绝对是属贼的,好好的人不做,你做梁上君子?
诸小亮:“行了,起床了,看看这都几点了,你老是睡过”
其实知道这人是诸小亮后,张小飞已经不紧张了,不过还是很生气,说到:“那你也不能这样啊,不知道人吓人,吓死人啊,不会敲门吗?”
“敲门?我整整敲了10分钟的们,你都没听见,这不是没办法吗?”
“其实…,我听见了”
“听见了,你还不起来开门?”
“我梦里正在吃火锅,隔壁装修,咚咚咚,烦死了,就没管”
“…”
4. 方法
十分钟后。
诸小亮:“今天咱们学习一个新的东西:方法”
张小飞:“这是个什么东西?”
诸小亮:“简单来说:是一段具有特定功能的代码”
“。。。。。。,不懂”
1. 定义
诸小亮:“没关系,先看看它的定义”
修饰符 返回值类型 方法名(参数类型 参数名称1,参数类型 参数名称2,...)
{
执行语句;
return 返回值;
}
“你这…,搞得,更看不懂了,什么修饰符、返回值的”
诸小亮:“不要急,会慢慢跟你说的”
2. 为什么需要方法?
诸小亮:“先给你一个需求:打印 * 号,每行打印 5 个 * 号,打印 5 行”
张小飞:“这个太简单了”
public static void main(String[] args){
System.out.print("*****");
System.out.print("*****");
System.out.print("*****");
System.out.print("*****");
System.out.print("*****");
}
诸小亮:“额…,其实我是想让你用 for 循环去实现”
“那不是昨天讲的东西吗?”
“是啊,怎么了?”
“我这个人,从来不回头看过去的事”张小飞说到
诸小亮:“滚蛋,别废话,赶紧用 for 在来一遍”
张小飞:“…,好吧,好吧,满足你”
public static void main(String[] args){
for(int i = 0;i<5;i++){
for(int j = 0;j<5;j++){
System.out.print("*");
}
System.out.println();
}
}
“嗯,不错,如果再给你一个需求:还是打印 * 号,每行打印 3 个 * 号,打印 3 行,你怎么做?”
“…”张小飞像看白痴一样的看着诸小亮“这就更简单了,复制上面代码,改一下不就行了?”
public static void main(String[] args){
//需求1:打印 * 号,每行打印 5 个 * 号,打印 5 行
for(int i = 0;i<5;i++){
for(int j = 0;j<5;j++){
System.out.print("*");
}
System.out.println();
}
//需求2:打印 * 号,每行打印 3 个 * 号,打印 3 行
for(int i = 0;i<3;i++){
for(int j = 0;j<3;j++){
System.out.print("*");
}
System.out.println();
}
}
诸小亮:“咱们来分析一下这两段代码,功能差不多,都是打印 * 号”
张小飞:“确实是这样,但一个是打印 5 行,一个是 3 行,这也不算问题啊”
“如果给你 N 个这样类似的需求呢?你难道要把复制 N 遍?”
“额…,我明白你的意思,你是想说它们很类似,却不能重复使用对吧?”
“是的,这种方式的问题是代码的复用率极其低下,使用 ‘方法’可以这个问题,比如:”
/**
* 既然功能一样,代码也差不多,就写一个方法专门用来打印 * 号, 用来提高代码的复用性
*
* 定义一个方法:专门用来打印*号,这样如果有类似的需求,直接调用这个方法就行
*
* 另外这个方法需要两个参数:
* row 表示要打印几行
* column 表示每行打印多少个 * 号
*/
public static void print(int row, int column){
for(int i = 0;i < row;i++){
for(int j =0;j< column;j++){
System.out.print("*");
}
System.out.println();
}
}
public static void main(String[] args){
//需求1:每行打印 5 个 * 号,打印 5 行
print(5, 5);//调用自定义的方法,(5, 5)相当于设置它的两个参数:row=5,column=5
System.out.println("----------华丽的分割线-----------");
//需求2:每行打印 3 个 * 号,打印 3 行
print(3, 3);
}
结果:
“上面的代码,你能看懂吗?”
“大概可以看懂,不过还是得麻烦您解释一下”张小飞说到
“这是自然,不过有些东西现在确实接触不到,会到以后再说”
1. public 和 static 是修饰符(Java中的关键字),以后再说
2. void:表示这个方法没有返回值,有些方法是有返回值的,稍后详述
3. print:**自定义的方法名,要符合标识符的规则,同时也要有意义,别用一些aa,bb,cc**
4. int row:**参数类型 和 参数名称(自定义),多个参数之间用"," 分隔**
“。。。,师兄,您这不行啊,一共 4 条,就解释了 2 条”
“没办法,先这样用吧,前两条后面会介绍的,其实这里最重要的是要记住:”
方法的作用:提高代码的复用性
3. main 方法
张小飞:“我们用的这个 main 也是一个方法吧,但是这个参数???”
诸小亮:“没错,但是 main方法比较特殊,被称为主方法,是 Java 程序的入口,执行 java 命令后,会首先进入 main 方法,同时也可以传递参数,比如(代码中会对参数解释):”
class Demo{
public static void main(String[] args){
System.out.println("main方法的参数是:");
//打印 args 参数,args是字符串数组,还没学
for(int i =0;i<args.length;i++){
System.out.println(args[i]);
}
}
}
结果:
张小飞:“我是想问 String[] args 这个参数是什么意思”
诸小亮:“这个是数组,讲完方法,我们就会说到数组了,再等一会儿”
4. return
张小飞:“对了,在说方法定义的时候,还有一个 return 的东西,这是做什么的?”
诸小亮:“return:表示方法的结束,方法中必须有这个东西,格式:return 返回值;”
“不对吧,上面定义的 print 方法中就没有 return”
“因为:print 方法的返回值是 void,**如果一个方法返回值类型是void,那么 return 可以省略,**当然即使是 void ,也可以写上 return,比如:”
“原来是这样,如果返回值不是 void 呢?”
“来,看看下面的这个 num 方法,你就明白了”
/**
* 该方法用来计算一个数跟 2 的乘积,并返回计算后的结果
*/
public static int sum(int a){
int result = a * 2;
return result;//该方法有具体的返回值类型,所以 return 不可少
}
public static void main(String[] args){
// 调用有返回值的方法,既然有返回值,就需要对应的变量去接收
int result = sum(10);
System.out.println(result);
}
结果:
“明白了,我也来试一试”张小飞说到
5. 重载
诸小亮:“接着我们介绍方法中最后一个知识点:重载”
重载:是一种现象,具体表现:多个方法的名称一样,但是 参数类型 或 参数个数 不同
“师弟,这个概念一定要记住”
“明白,不过这个重载能不能给个例子?”
“这个简单,看下面代码:”
//该方法用来计算两个整数的和
public static int sum(int a, int b){
return a + b;
}
//该方法用来计算两个小数的和
public static double sum(double a, double b){
return a + b;
}
“师兄,上面代码有两个方法,但是参数类型和返回值不同,这就是:方法重载?”
“是的,不过方法的重载跟返回值无关,只需要关注:参数类型 和 参数个数”
“哦,那么重载具体是有什么作用呢?”
“没有什么特别大的作用,其实就是告诉你:方法名可以重复”
“。。。。。。”
“最大的作用:当方法的功能都一样,只参数不同时,没有必要起新的名称,用同一个名称即可,比如:”
//常用的print方法,就有很多重载形式
public void print(boolean b)
public void print(char ch)
public void print(int i)
public void print(double x)
“好吧,原来就这么点儿用处”
5. 数组
诸小亮:“接下来我们就开始学习:数组”
张小飞:“什么是数组呢?”
“数组—就是:一组数”
“。。。。。,这有什么用?”
1. 引入
诸小亮:“先看一下,之前我们写的求和方法:”
张小飞:“这个方法有什么问题嘛?”
“这是我写的,怎么可能有问题,不过上面是对两个整数的求和,如果需要对 3 个正数的求和呢?”
“这简单,仿照上面的方法,写一个重载方法不就行了?”张小飞说到
public static int sum(int a, int b, int c){
return a + b + c;
}
“那如果需要对100、1000个数字求和呢?你还能用重载方法吗?”
“这——,您的意思是,用数组?”
“没错,通过数组可以解决这种多参数的问题”
2. 定义
诸小亮:“先了解一下数组的定义:”
- 数组:一组数据的意思,是同一种类型的数据集合,一般称数组中的数据为:元素
- 定义:元素类型[] 变量名 = new 元素类型[元素个数]
示例:
public static void main(String[] args){
int[] arr = new int[3];// 定义一个 int 类型的数组,长度是3(表示能存放3个int类型的数字)
}
张小飞:“那具体怎么使用呢?”
“数组中的数据默认都有编号(从0开始,也叫索引、下标),利用编号能方便的操作数据,比如:”
结果:
“师兄,你刚才只是定义数组,还没往里面存数据吧,怎么就有值了?”
“是的,不过创建数组时都会设置默认值,不同类型的数组,默认值也不同”
int、long、short--------0
double---0.0
boolean--false
“那么如何才能往数组中添加数据呢?”
“设置数据也是通过编号,比如:”
结果:
“原来是这样,那么设置其他元素就是 a[1]=10; arr[2]=11 这样的?”
“是的,你自己尝试一下吧”
3. 常见错误
张小飞:“这里出问题了,您来看一下”
诸小亮:“这是数组中一个常见的错误,原因是:尝试获取不存在的数据”
ArrayIndexOutOfBoundsException(数组下标越界),因为想获取不存在的下标
“不存在?不会啊,不是一个三个数么,怎么会不存在?”
“是这样的:数组中的元素从 0 开始编号,存 3 个元素的数组,它里面最大的编号是 2”
“原来是这样,我明白了”
“另外,还需注意一点:不要操作空数组”
“空数组?”张小飞问到
“空:表示没有任何东西,下面就是空数组:”
“上面代码,运行后会提示:**NullPointerException(空指针异常),**比如:”
“好的,好的,又学到了”
4. 另一种方式
诸小亮:“其实定义数组还有另外一种方式,在创建数组时,直接指定数组中的内容”
示例:
public static void main(String[] args) throws IOException {
//创建数组时,直接指定数组中的内容,格式:元素类型[] 变量名 = new 元素类型[]{元素1,元素2......}
int[] arr = new int[]{1,2,3};
System.out.println(arr[0])
}
张小飞:“嗯嗯,这样子确实方便不少”
“还有更方便的:”
“不过这种方式很少使用,了解一下就行” 诸小亮补充道
5. 遍历数组
张小飞:“遍历数组是什么意思?”
诸小亮:“其实就是用 for 获取数组中的每个元素?”
“for循环?要怎么实现?”
“数组有个 length 属性,表示数组的长度,用它就可以遍历数组,比如:”
public static void main(String[] args) throws IOException {
int[] arr = {1,2,3};
//遍历数组,数组中有几个元素length的值就是几
for(int i = 0; i<arr.length; i++){
System.out.println(arr[i]);
}
}
结果:
张小飞:“原来是这样”
6. 求和练习
诸小亮:“好了,既然知道如何遍历数组,我们就写个方法,尝试对数组中的数据进行求和”
张小飞:“这就让我来吧”
//该方法,计算一组整数的和
public static int sum(int[] arr){
int sum = 0;
for(int i =0; i<arr.length; i++){
sum = sum + arr[i];
}
return sum;
}
public static void main(String[] args){
//求3个数的和
int[] arr = {1,2,3};
int res = sum(arr);
System.out.println(res);//6
//求6个数的和
int[] arr2 = {1,2,3,3,4,6};
int res2 = sum(arr2);
System.out.println(res2);//19
}
诸小亮:“嗯,不错,不错”
7. 最值问题
诸小亮:“下面咱么说说最值问题”
张小飞:“什么是最值问题?”
“就是给你一个数组,然后获取它的最大值,比如:{1,2,3,3,4,6} ”
“这还不简单,6”
“。。。。不是让你用眼看,而是用代码写,如果给你 1000 个数字,你也用眼看吗?”
“哦哦,用代码…,怎么写?”
“首先,我们分析一下这个需求:因为是一组数,所以考虑使用数组 ”
“嗯嗯,1000个数肯定得用数组”张小飞说到
“接着,先拿前 2 个数比较,得出一个比较大的值(num)”
“然后呢?”
“然后,用 num 跟第三个数字比较,又能得出一个比较大的值。。。。。。依次类推。”
“我明白了,就这样将数组中的元素都比较一遍,就能得出最大值”
“你说的没错,其代码:”
public static void main(String[] args) throws IOException {
//求 arr 中的最大值
int[] arr = {1,2,3,3,4,6};
//1. max用来记录最大值,这里是先假设第一个数是最大值
int max = arr[0];
for(int i = 1;i<arr.length;i++){
//2. 循环数据中的元素,每一个都跟 max 比较
if(arr[i] > max){
//3. 如果元素大于max, 记录这个数
max = arr[i];
}
}
System.out.println(max);//最终输出:6
}
“很简答啊” 张小飞说到
“不错,不过这个只是为数组排序打打基础”
8. 排序
张小飞:“排序,是对数组中的数组进行排序吗?”
诸小亮:“是的,对数组的元素进行排序,这是很常见的一种需求”
张小飞:“既然都能计算出最大值了,那么排序当然没有问题”
“哦?那你来试试,对一组数从小到大排序,比如:[3, 2, 5, 8, 1]”
“好啊,给我 5 分钟”
“不用着急写代码,先告诉我你的思路是什么?”诸小亮急忙拦着
“思路是这样的:”
- 从小到大排,那么最后一个元素就是最大值
- 第一步:数组中的 arr[0] 跟 arr[1] 比较,3>2,交换它俩的位置,结果:[2, 3, 5, 8, 1]
- 第二步:arr[1] 跟 arr[2] 比较。。。。。。,以此类推
- 最后第 arr[3] 跟第 arr[4] 比较,8 >1,所以它俩交换,结果:[2, 3, 5, 1, 8]
诸小亮:“嗯,不错,不过你这样仅仅是把最大值 8 放到了正确的位置上,其他的还是乱序”
张小飞:“还没说完呢,上面只是第一轮比较,计算出最大值并放到最右边”
- 接下来进行第二轮比较,把第 2 大的值放到下标为 [3] 的位置。。。。。。,以此类推
“没错,其实你的这种方式称为:冒泡排序,每一轮都比较出一个最大值放到指定位置”
诸小亮:“既然这样,你就写一下代码吧”
张小飞:“没问题,稍等一下”
五分钟后。
张小飞:“代码已经写好了”
public static void main(String[] args) throws IOException {
//需要排序的数组
int[] arr = {3,2,5,8,1};
//1. 外层for循环:控制一共比较几轮
for (int i = 1; i < arr.length; i++) {
//2. 内存for循环:找出每一轮的最大值,并放到指定位置
for (int j = 0; j < arr.length - i; j++) {
//2.1 相邻元素相互比较,如果左边元素大, 就交换位置
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
//3. 每一轮比较结束后,遍历数组
for(int k = 0; k<arr.length; k++){
System.out.print(arr[k]+",");
}
System.out.println();
}
}
结果:
9. 二分查找
诸小亮:“小时候,你有没有玩过一种猜数字的游戏?”
张小飞:“猜数字?什么游戏?”
“你心里先1-100之中的一个数字,我来猜,每猜测一次,你要告诉我(大了、小了、相等)”
“哦~~,这种游戏啊,当然玩儿过,如果你猜50,我说大了,那么数字一定在1-49之中,对不对?”
“是的,一下缩小一半范围,这种专业说法是:二分查找,也叫:折半查找”
“哦哦,怎么突然之间说起这个了?”
“我希望你能在 [1,2,3,12,24,25,33,62,99] ,这个有序数组中找到,数字 12 的下标是多少”
“这还不简单,下标就是…1,2,3…,哦,不对,应该是0,1,2…,找到了, 12 的下标是 3”
“。。。。。,不是让你一个个数,而是用 二分查找 的方式” 诸小亮说到
“这样啊,你不早说”张小飞不满的白了诸小亮一眼
“好好好,是我不对,没有说清楚,现在再说说你的思路吧” 诸小亮无奈道
“让我想想,利用二分查找,要查的数是 12…,我想到了:”
- 先根据 起始坐标0 和 最大坐标8 计算出中间元素的下标4,进而拿到对应的值 arr[4]
- 如果 arr[4] > 12 ,那么 12 就在,下标为 0 - 3 之间
- 如果 arr[4] < 12 ,那么 12 就在,下标为 5 - 8之间
- 上面数组 arr[4] = 24,表示 12 在下标为 0 - 3 之间
- 接下来,计算 0 - 3 的中间元素下标。。。。。以此类推
诸小亮:“你说的不错,不过如果给你的数字在数组中就不存在呢?比如:6”
张小飞:“不存在?按照上面的思路:”
- 第一次:arr[4] > 6,那么 6 就在,下标为 0 - 3 之间
- 第二次:arr[1] < 6,那么 6 就在,下标为 2 - 3 之间
- 第三次:arr[2] < 6,那么 6 就在,下标为 3 - 3 之间
张小飞:“这时候 起始坐标 和 最大坐标 的值一样了,没办法再次查找了,也就不能循环了”
诸小亮:“完全正确,那么你能用代码把你这个思路写出来吗?”
张小飞:“嗯…,我尽量试试吧”
//该方法:用于查找 num 在 arr 中的下标
public static int binarySearch(int[] arr, int num){
int max = arr.length-1;//最大下标
int min = 0;//最小下标
int mid;//中间元素下标
//当 最小下标 >= 最大下标时,循环结束,说明数组中没有对应的数字
while(min >= max){
//1. 计算中间下标
mid = (max + min) / 2;
//2. 如果 arr[mid] > num,那么它一定在 min ~ (mid-1) 之间
if(arr[mid] > num){
max = mid - 1;
}else if(arr[mid] < num){//3. 如果 arr[mid] < num,那么它一定在 (mid+1) ~ max 之间
min = mid + 1;
}else {
return mid;//4. 如果 arr[mid] == num,直接返回 mid
}
}
return -1;//-1表示num不再arr数组中
}
public static void main(String[] args){
int[] arr = {1,2,3,12,24,25,33,62,99};
int res = binarySearch(arr, 62);
System.out.println(res);
}
结果:
10. 二维数组(了解)
张小飞:“师兄,这个二维数组是???”
诸小亮:“二维数组:其实就是多个一维数组,上面介绍的都是一维数组,比如:”
“哦,是这样,那二维数组应该怎么用呢?”
“也很简单,它的定义:数据类型[][] 变量名 = new 数据类型[3][4];”
“上图:定义了一个 3 行 4 列的二维数组,其实就是3个一维数组,每个一维数组中可以存 4 个 int 数字”
张小飞:“那,是这样获取数组中的数据吗?”
诸小亮:“是的,上图表示:获取第 1 个一维数组中的第 2 个元素”
诸小亮:“另外,还有第二种定义方式:”
“这个就有些看不懂了” 张小飞说到
“其实就是定义了一个有 3 个一维数组的二维数组:”
第一个一维数组:{1,2,3}
第二个一维数组:{4,5,6}
第三个一维数组:{7,8,9}
“原来如此”
6. 用户输入
诸小亮:“下面我们介绍一个特殊的知识,获取‘用户输入’”
张小飞:“‘用户输入’?,要怎么输入?又怎么获取?”
1. 处理用户输入
诸小亮:“在运行 Java 程序时,使用 Scanner 可以接收用户的输入,比如: ”
// import还未讲,先使用
import java.io.*;
import java.util.Scanner;
class Demo{
public static void main(String[] args) throws IOException {
System.out.println("请输入:");
Scanner sc = new Scanner(System.in);
// nextLine:获取用户输入的一行数据,
String s = sc.nextLine();//当程序执行到 sc.nextLine() 时,会等待用户输入,用户输入后按回车代码才接着执行
System.out.println("您输入的是:" + s );
sc.close();
}
}
张小飞:“这段代码中,有很多东西都没有见过啊”
“我先给你解释一下:”
- 最上面的 import 还未讲到,我们先用
- Scanner :是 Java 提供的用来处理用户输入的一个工具
- nextLine是一个方法:当执行这句代码时候,程序会等待我们输入,输入后按回车代码才接着执行
“那,在哪里输入东西呢?”张小飞问到
“在命令行,先把程序跑起来,你来看看”
“有意思,有意思,我也来试一试”
2. 求和
诸小亮:“既然可以接收用户输入,那么就来个需求:根据用户输入的两个数字,求它们的和?”
张小飞:“师兄,您要求输入两个数字,上面演示的只是接收用户输入的一句话,这个…”
“不好意思,是我的疏忽,那就我来吧,其实接收用户输入的数字用 nextInt() 就行了,比如:”
public static void main(String[] args) throws IOException {
System.out.println("请输入两个数字:");
Scanner sc = new Scanner(System.in);
//nextInt:获取用户输入的数字,多个数字之间使用空格隔开
int num1 = sc.nextInt();//获取第一个数字
int num2 = sc.nextInt();//获取第二个数字
System.out.println("和是:" + (num1 + num2));
sc.close();
}
结果: