乐趣区

方法和数组就是这么简单

第三章 方法和数组

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 技术的公众号:理想二旬不止

退出移动版