共计 5248 个字符,预计需要花费 14 分钟才能阅读完成。
第三章 方法和数组
3.1 概述
还记得我们的 HelloWorld 例程吗?我们现在对于输出语句应该已经很熟悉了,
解释:
System 是系统类。
out 是标准输出对象
println() 是一个方法。
如果我们想要在一个类中实现很多功能,但是如果我们想要,多次使用,某一个功能,显然我们需要重复书写这个功能的代码多次,显然,这是不明智的。所以方法就来拯救我们了。
❤ 3.1_1 方法的基本定义
定义:方法是定义在类中的一段独立的代码块,用来实现某个功能。
其实我们在编程界中更喜欢叫它们为函数,但是在 Java 中我们也可以叫做方法
作用:
·函数的主要作用是为了提高代码的复用性。
·使程序简短而清晰,更加利于维护
A:修饰符:public static(暂时了解这一个 后期补充)
B:返回值类型:就是功能结果的数据类型
有一些方法执行代码中的命令即可,执行后就可以结束了,并没有返回值(void)
有一些方法需要将最后的结果返回给你,从而让开发者使用这个结果
举例更好理解哦:最近有一场周杰伦的演唱会,我通过好多朋友帮忙一起的抢票方法,最后得到了两张票,这两张票就是“抢票”方 > 法的返回值,我(开发者)可以对这个返回值进行任何操作,例如自己去看,或者送给朋友,甚至可以用来当草稿纸(哭 …)
C:参数类型:参数的数据类型
主方法可以调用其他方法,其他方法可以互相调用,但不能调用主方法,主函数是系统调用的。
❤ 3.1_方法(函数)的调用方法:
A:单独使用,一般来说没有意义(不代表有错),所以不推荐
B:输出调用,但是不够好,因为我们可能需要针对结果进行进一步操作
C:赋值语句,推荐方案。
方法的调用优化:
Eg:比较两个数是否相等(在没有熟练之前我们仍然推荐使用初始直观的用法,程序可以正常的跑是我们的底线)
❤ 3.1_3 方法重载
一般来说,我们都是根据作用来命名方法(方法名有意义),但是很多时候会我们会针对 不同的数据类型,或者参数个数 来进行操作,例如我们所要求几个数字中的最大值问题(如下图)就出现了这两种问题。使用方法重载,既可以保证命名有意义,也可以避免记忆过多的不同名称
定义:用同一方法名定义多个方法,这些方法的参数个数或者参数类型不同
作用:使一个方法名赋予新的含义,使一个方法名可以多用
适用:实现细节不同的同一类功能时候
理解:其实就是使得一个方法拥有了 更多的可能性,一个名称解决多种问题。
注意:
1. 函数的返回类型不同,但参数个数和类型相同,不是重载
2. 重载函数的的参数个数,参数类型,参数顺序至少有一个需要不同
3.2 数组
引文:我们在篮球场比赛中,梦之队运动员共有 10 名,我们分别将每个人定义为几号运动员,这样我们找某一个人的时候,我们就会先找到梦之队这支队伍,然后去找对应编号的人。
而数组就像这只队伍的概念一样,而数组中的每一个元素就是每一个球员,当你需要找数组的某一个元素的时候,只需要找到你需要查找的数组(梦之队),再根据数组下标(对应编号)去寻找对应元素(球员)。
这样做的好处就是,我们将一批同类型的元素整理归纳到了一起,并且标号记录。
既方便了查找与使用,又避免了定义多个变量的麻烦。
概念:以存储一个固定大小的相同类型元素的顺序集合。
数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
(所有的数组都是由连续的内存位置组成)
格式:
第一种读法:定义一个 dataType 类型的数组 arrayRefvar 变量
第一种可以认为是 java 风格的定义格式,推荐第一种,不过也只是编程风格不同罢了。
初始化:
A:概念:为数组开辟内存空间,为每个数组元素赋予值(内存分配问题就在下面哦)
B:方式:
a:动态初始化 → 只指定长度,由系统给出初始化值
b: 静态初始化 → 给出初始化值,由系统决定长度
A:动态初始化格式:
数据类型 [] 数组名 = new 数据类型 [数组长度];
Eg:int [] arr = new int [3];
B:静态初始化格式:
数据类型 [] 数组名 = new 数据类型 [] {元素 1,元素 2,…};
Eg:int [] arr = new int [] {1,2,3};
简化格式:
数据类型 [] 数组名 = {元素 1,元素 2,…};
Eg:int [] arr = {1,2,3};
数组的访问:
数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 数组长度 -1。(这只球队可是有 0 号选手的哦吼~)
进阶补充知识:
在 Java 中,数组是一种效率最高的存储和随机访问对象的引用序列的方式。数组就是一个简单的线性序列,这使得元素访问非常快速。但是为这种速度所付出的代价是数组对象的大小被固定,并且在其生命周期中不可改变。你可能会建议使用 ArrayList,它可以通过创建一个新实例,然后把旧实例中所有的引用到移到新实例中,从而实现更多空间的自动分配。尽管通常应该首选 ArrayList 而不是数组、但是这种弹性需要开销,因此,ArrayList 的效率比数组低很多。
——Thinking in Java 第 16 章
❤ 3.2_1 java 中的内存分配
Java 为了对数据进行空间分配而划分的 5 个内存空间
栈区(stack area) | 函数中定义的基本类型变量,对象的引用变量(对象在堆上的地址)都在函数的栈内存中分配。 |
---|---|
栈内存特点,数数据一执行完毕,变量会立即释放,节约内存空间。 | |
栈内存中的数据,没有默认初始化值,需要手动设置。 | |
堆区(heap area) | 堆内存用来存放 new 创建的对象和数组。 |
堆内存中所有的实体都有内存地址值。 | |
堆内存中的实体是用来封装数据的,这些数据都有默认初始化值。 | |
堆内存中的实体不再被指向时,JVM 启动垃圾回收机制,自动清除,这也是 JAVA 优于 C ++ 的表现之一(C++ 中需要程序员手动清除)。 | |
方法区(Method Area) | 存储所有类(class)和静态变量(static) |
本地方法区(Native Method Area) | 后期补充 |
寄存器 | 后期补充 |
❤ 3.2_2 常见数组练习
(一)遍历数组
理解:简单来说就是把数组中的每一个元素都读一遍,你可以对数组中的每一个数进行处理,又或者找到数组中那个你需要的数。
但是有时候就想鸭,每一次我的数组元素数量较少的时候还可以,我数一数有多少个元素也就知道我需要遍历多少次了,但是如果数组元素太多呢,又或者我把遍历数组编写成一个方法,参数就是一个数组,不同的数组(元素数量不同),很显然需要遍历的次数是不灵活的,所以我们介绍一个更为灵活的属性——length
针对元素数量较多的数组 可以使用 length 属性 获取数组的长度
(二)获取数组中的最小值或最大值
思路:
从数组中任意找一个元素作为参照物
然后遍历其他的元素
一次获取和参照物进行比较,如果大就留下来,如果小就离开
(三)数组逆序
❤ 3.2_3 For-Each 循环
JDK 1.5 引进了一种新的循环类型,被称为 For-Each 循环 或者 增强 For 循环,它能在不使用下标的情况下遍历数组。
格式:
它的功能强大就在于不必为了下标的起始值和终止值而分心,代码更加简洁,更不容易出错。
事物总是有两面性的,虽然增强 for 循环带来了简洁和快速,但是并不是万能的,有的时候我们必须使用传统的 for 循环,例如不希望遍历每一个元素,或者在循环内部需要使用下标等。
补充:
如果仅仅是想要打印数组中的所有值,我们可以利用 Arrays 类中的 toString 方法
输出后格式如下:“[1,3,6,5,6]”
❤ 3.2_4 排序方法
贫穷使我面目全非……〒_〒
假如我想在某宝买一本五年高考,三年模拟(搞笑脸),又担心买到的不是正版印刷(再次搞笑),我们可以选择销量优先展示商品,而我们又嫌贵又渴望知识的时候(哈哈哈~),我们又可以选择价格从低到高排序展示商品。
那么,网站是如何做到快速将商品按照某种规则排序的呢?
下面我们就来介绍几种常见的排序方法
数组是用来存储一些数据的“容器”,可能我们需要将其中的元素,按照我们一定的规则进行处理,使其成为有序的序列。
(一)冒泡排序
我们先通过一个直观的例子来看一这种排序方法是如何操作的呢
要排序的数组 int[] = {3, 9, 6, 5};
第一趟排序:
第一次排序:3 和 9 比较,3 小于 9,不交换位置:3 9 6 5
第二次排序:9 和 6 比较,9 大于 6,交换位置:3 6 9 5
第二次排序:9 和 5 比较,9 大于 5,交换位置:3 6 5 9
————————————————————————————
第二趟排序:
第一次排序:3 和 6 比较,3 小于 6,不交换位置:3 6 5 9
第二次排序:6 和 5 比较,6 大于 5,交换位置:3 5 6 9
————————————————————————————
第三趟排序:
第一次排序:3 和 5 比较,3 小于 5,不交换位置:3 5 6 9
根据上图的规律,我们得到了冒泡排序的原理:
重复地走访要排列的元素列,一次比较两个相邻的元素,如果它们的顺序错误则交换
走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序 完成。
为了理解这个看起来很复杂的定义,我们来梳理一下上面的例子:
第一趟:经过三次排序,得到结果:3 6 5 9
第二趟:经过两次排序,得到结果:3 5 6 9
第三趟:经过一次排序,得到结果:3 6 5 9
(第三趟也是存在的只不过是,在第二趟的时候结果已经符合规定,)
我们通过梳理可以看到
我们在第一趟中,4 个数字,经历了 3 次排序,确定了最大值
在第二趟中,3 个数字(最后一位已经确定,所以不计),经历了 2 次排序,确定了最大值
在第三趟中,2 个数字(倒数两位已经确定,所以不计),经历了 1 次排序,确定了最大值
慢慢的最大值或者最小值(根据排序规则)会像气泡一样浮到数列的顶端,故得名冒泡排序
思路
1:外层循环:控制它要走几次。
假设你有 5 个数,那就要走 4 次,最后一次不用走,最后那个数已 经在它位置了所以就要 length- 1 次。
2:内层循环:控制逐一比较,如果发现前一个数比后一个数大,则交换。
注意!因为越比较长度就越小了,所以长度要 length-1-i。
所以:n 个元素进行排序,我们需要进行 n -1 趟,每一趟循环 lenght-1- i 次
Ps:length- 1 代表最后一项,数组下标从 0 开始
冒泡排序只是我们众多排序中的一种比较简单的方法(效率不是很高,但入门必须学习)
其他的排序方法,我们放到板块数据结构与算法中详细讲解
要想对数值型数组进行排序,可以使用Array 类中的 sort 方法
格式:int[] arr = new int [520];
……..
Array.sort(arr)
sort 方法本质是快速排序算法(高效快速)
❤ 3.2_5 二维数组
具有两个下标的数组称为二维数组。有些数据要依赖于两个因素才能惟一地确定
例如我们下面的这个案例一个班级有三个学生,每个学生又对应四科成绩,所以我们必须用一个二维数组来存储,第一项储存学生信息,第二项存储成绩信息
Student Number | Course1 | Course2 | Course3 | Course4 |
---|---|---|---|---|
Student1 | 55 | 66 | 58 | 77 |
Student2 | 87 | 58 | 48 | 64 |
Student3 | 65 | 78 | 70 | 56 |
Java 中,二维数组中元素排列的顺序是:
定义格式:
A:
B:
从最高维开始,分别为每一维分配空间
如果想要在定义的时候就直接赋值,格式见例题中的示例
❤ 3.26 常见二维数组练习
(一)遍历二维数组
(一)普通 for 循环版
(二 ) 增强for 循环版
(三 )Arrays 类中的 deepToString() 方法
这个方法可以快速 打印一个二维数组的数据元素列表
(二)输出杨辉三角
3.3 补充问题
❤ 3.3_1 参数传递问题
开局一张图,内容全靠编~
有了前面知识的一些铺垫,我们终于可以引出这个问题了, 诺,下面题目中利用方法重载给出了两个不同参数的 change 方法,分别在主函数中输出调用方法前和后的数据,看一看输出的数据和我们所想的一样吗?
小白:变量 a 和 b 在 change 方法中已经被重新赋值了,第二局输出那必然是 a=20, b=40
大佬:错!错!错!正确结果为输出 a=10, b=20小白:虽然我也不太明白,但是有了第一个的经验,那我第二个我还不会吗,arr[1] 当然是 2 了
大佬:em…… 答案是 4 …….
(绝望脸 …)
然后我们通过一张图来分析一下这个问题
解释:
当基本类型作为形式参数的时候 ,实际参数(也就是主方法中的 10 和 20)的值传到了 这个方法中,无论其如何操作运算, 均只是对被传入的值进行操作,方法结束后即消失,不会对实际参数有任何的影响
当引用类型作为形式参数的时候 , 实际参数和形式参数均指向了同一个地址,所以形式 参数的改变会直接影响到实际参数
总结:
基本类型:形式参数的改变对实际参数没有影响
引用类型:形式参数的改变直接影响实际参数
❤ 3.3_2 加密问题(作为练习)
加密规则:将数据倒序,然后将每位数字都加上 5,再用和除以 10 的余数 代替该数字,最后将第一位和最后一位数字交换
结尾:
如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家!^_^
如果能帮到你的话,那就来关注我吧!
在这里的我们素不相识,却都在为了自己的梦而努力 ❤
一个坚持推送原创 Java 技术的公众号:理想二旬不止