2-7 函数
1.什么是方法(Method)?
结构化代码
将代码按照功能进行组织,使代码的结构比较清晰,容易阅读和修改,也就是程序的可维护性强。
减少代码重复
一个固定的功能,可能会在程序中多次使用,在使用时只需要调用写好的方法,而不用重复书写对应的功能代码。
方法在书写时需要注意以下两点:
逻辑严谨
方法实现的一个完整的功能,所以在书写时要考虑到各种可能的情况,并对每种情况做出恰当的处理。
通用性强(可重复利用)
方法实现的是一种功能,在实际实现时,可以根据需要,使方法具备一定的通用性,除非必要,否则不要写专用的方法。在Java 语言中,恰当的使用方法,将使程序更加优雅,便于阅读和使用。
总结:方法:一段可重复使用的代码段,程序中完成独立功能的一段代码的集合。
2.Java中方法的格式
[修饰符] 返回值类型 方法名([参数类型 形式参数1,参数类型 形式参数2,……]){
执行语句 [return 返回值;]//需要的话
}
参数列表(参数的类型 ,参数的个数,参数的顺序)
总结:只要上述有一个不一样,那么这个参数列表就不一样!对于方法而言,即使同名也不是同一个方法,也就是下面讲的方法签名。
3.方法里的属性
访问控制符:访问控制符限定方法的可见范围,或者说是方法被调用的范围。方法的访问控制符有四种,按可见范围从大到小依次是:public、protected,
无访问控制符,private。其中无访问控制符不书写关键字即可。具体的范围在后续有详细介绍。
形式参数:在方法被调用时用于接收外界输入的数据。实参:调用方法时实际传给方法的数据。
返回值:方法在执行完毕后返还给调用它的环境的数据。
返回值类型:事先约定的返回值的数据类型,如无返回值,必须给出返回类型 void。
java语言中调用方法:对象名.方法名(实参列表)。
实参的数目、数据类型和次序必须和所调用方法声明的形参列表匹配。
return 语句终止方法的运行并指定要返回的数据。
4.方法特点
它可以实现独立的功能;必须定义在类里面;它只有被调用才会执行;它可以被重复使用;方法结束后方法里的对象失去引用;
如何定义一个功能,并通过方法体现出来:
明确该功能运算后的结果.明确返回值类型;明确在实现该功能过程中是否有未知内容参与运算,确定参数列表;
(1).定义函数可以将功能代码进行封装,便于对该功能进行复写。
(2).函数只有被调用才会被执行。
(3).函数的出现提高了代码的复用性。
(4).对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的 return语句如果在最后一行可以省略不写。
(5).函数中只能调用函数,不可以在函数内部定义函数。
(6).定义函数时,函数的结果应该返回给调用者,交由调用者处理。
(7).可以自定义一个访问权限。
注意:
(1).功能中只定义所需内容,不是该功能所需的内容不要定义。
(2).如果非要定义,也是单独定义一个功能来体现。以后开发时,尽量都将功能以不同的函数来体现。
(3).不要将代码都定义在主函数中。
(4).主函数的作用是:对已有的功能的进行调用,可以理解为用于功能的测试。
(5).函数名就是一个自己定义的标示符。函数名的定义,要尽量体现出这个函数的功能。是为了增强该函数的阅读性,方便于调用者使用,所以函数名一定要有起的有意义。
(6).静态方法只能调用静态方法。主函数是静态的。
(7).返回值类型和参数类型没有直接关系。
5.方法的应用
明确要定义的功能最后的结果是什么?
明确在定义该功能的过程中,是否需要未知内容参与运算。
示例1:
需求 :定义一个功能,完成两个整数的和的获取。
思路 :既然定义功能,就可以用函数来体现。
通过两个明确来完成:
明确一:这个功能的结果是什么?是和。是功能的结果,所以该功能的返回值类型是int。其实就是在明确函数的返回值类型。
明确二:这个功能实现过程中是否需要未知内容参与运算?有,加数和被加数。这就是函数的参数列表(参数的个数,参数的类型)。其实就是在明确参数列表。
注意:
返回值类型和参数类型没有直接关系。
需求 :定义一个功能,画一个矩形在控制台。
明确一 :这个功能结果是什么?
没有结果,因为直接打印到了控制台,并未返回给调用者。用void表示。
明确二 :这个功能实现过程中是否需要未知内容参与运算?
有,行和列不确定,两个,整数int类型。
6.什么是方法的重载(Overload)?
概念:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型或参数顺序不同即可。
存在的原因:
屏蔽了一个对象的同一类方法由于参数不同所造成的差异。
特点:
与返回值类型无关,只看参数列表。
重载的好处:
方便于阅读,优化了程序设计。
总结:方法重载,方法名相同,但是参数列表不一致!(和方法覆写不一样,方法覆写的方法名和参数列表都必须一样),注意方法重载和方法覆写的不同!
2-8 数组
2-8-1 概念
同一种类型数据的集合。简单的来说就是一容器,用来装东西的。
使用数组的好处:可以自动给数组中的元素从0开始编号,方便操作这些元素。
2-8-2 一维数组的格式
格式1:元素类型 [ ]数组名 = new 元素类型 [元素个数或数组长度] ;如: int [] arr = new int [3]; 也可以写成: int arr[] = new int[3];
格式2:元素类型 []数组名 = new 元素类型 [ ]{元素1,元素2,…};
如: int [] arr = new int []{1,2,3,4,5};
还有一种简写的静态初始化格式:如: int [] arr={1,2,3,4,5};
其中:new是用来在堆内存中产生一个容器实体。
数组也被称为引用数据类型。在内存中的分配如下图:
Java程序在运行时,需要在内存中分配空间。为了提高运算效率,又对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
栈内存:
用于存储局部变量,当变量所属的作用域一旦结束,所占空间会自动释放。
堆内存:
数组和对象,通过new建立的实例都存放在堆内存中。
每一个实体都有内存地址值
实体中的变量都有默认初始化值,根据类型的不同而不同。整数类型是0,小数类型是0.0或0.0f,boolean类型是false,char类型是'\u0000'。
如果将数组的引用实体设置为null,也就是实体不再被使用,那么会在不确定的时间内被垃圾回收器回收。
2-8-3 数组操作常见问题
1、数组脚标越界异常(ArrayIndexOutOfBoundsException)。例:int[] arr = new int[2];
System.out.println(arr[3]);
访问到了数组中的不存在的脚标时发生。
2、空指针异常(NullPointerException)。例:
int[]arr = null;
System.out.println(arr[0]);
arr引用没有指向实体,却在操作实体中的元素时。
2-8-4 数组常见操作
对数组操作最基本的动作就是存和取。核心思想:就是对角标的操作。
常见操作一:获取最值(最大值,最小值)
思路:
1、需要进行比较,并定义变量记录住每次比较后较大的值。
2、对数组中的元素进行遍历取出,和变量中记录的元素进行比较。
如果遍历到的元素大于变量中记录的元素,就用变量该记录住大的值。
3、遍历结果,该变量记录就是最大值。
两个明确:
明确一:结果。
是数组中的元素:int类型。
明确二:未知内容。
数组。
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {89,34,-270,17,3,100};
int max = getMax(arr);
System. out.println("max = " + max);
}
public static int getMax(int[] arr){
int maxIndex = 0;
for(int x = 1; x < arr.length; x++){
if(arr[x] > arr[maxIndex])
maxIndex = x;
}
return arr[maxIndex];
}
}
常见操作二:排序(选择排序,冒泡排序)
选择排序:
思路:
1、首先拿数组第一个元素依次与除其自身外的其他每个元素顺序比较,如果第一个元素大于剩下的某个元素,就互换内容。
2、经过第一轮比较之后,此时第一个元素就是数组中最小的元素。然后再拿第二个元素与除第一个元素和其自身的元素进行比较,如果第二个元素大于剩下的某个元素,就互换内容。
3、依次类推,直到最后一个元素。
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {89,34,-270,17,3,100};
System. out.print("排序前数组:" );
printArray(arr);
selectSort(arr);
System. out.print("排序后数组:" );
printArray(arr);
}
public static void selectSort(int[] arr){
for(int x = 0; x < arr.length - 1; x++){
for(int y = x + 1; y < arr.length; y++){
if(arr[x] > arr[y]){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
public static void printArray(int[] arr){
System. out.print("[" );
for(int x = 0; x < arr.length; x++){
if(x != arr.length - 1)
System. out.print(arr[x] + "," );
else
System. out.println(arr[x] + "]" );
}
}
}
结果:
注意:
1、上面的selectSort方法之所以不用返回int数组的原因是因为:arr引用变量是对传入selectSort方法中作为参数的数组的引用,selectSort方法执行完毕之后,我们依然可以通过arr引用变量操作传入的数组。所以,没有必要再通过返回值获取。
2、上面的选择排序算法效率比较低,因为数组每一个元素与剩下的元素比较就是为了获得最小的元素并且与之互换。例如:{89,34,-270,17,3,100}这个数组,第一轮就要互换4次才能使第一个元素存储的是这个数组中最小的元素。如果是这样,那么更高效率的方式则是只需要通过两个变量,一个记录最小值,一个记录最小值所在的角标即可。等当前元素与余下的所有元素比较完,直接互换,这样只需互换一次就能达到目标,效率自然就会提高。
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {89,34,-270,17,3,100};
System. out.print("排序前数组:" );
printArray(arr);
selectSort(arr);
System. out.print("排序后数组:" );
printArray(arr);
}
public static void selectSort(int[] arr){
for(int x = 0; x < arr.length - 1; x++){
int num = arr[x];
int index = x;
for(int y = x + 1; y < arr.length; y++){
if(num > arr[y]){
num = arr[y];
index = y;
}
}
//如果最小的就是自己,就没有必要执行swap操作
if(index != x)
swap(arr,x,index);
}
}
public static void swap(int[] arr, int a,int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
public static void printArray(int[] arr){
System. out.print("[" );
for(int x = 0; x < arr.length; x++){
if(x != arr.length - 1)
System. out.print(arr[x] + "," );
else
System. out.println(arr[x] + "]" );
}
}
}
冒泡排序
思路:
1、首先在第一轮排序中,数组从第一个元素到倒数第二个元素依次与其右边的元素进行比较,如果左边的元素大于右边的元素,那么两个元素就互换。
2、经过第一轮比较,最大的元素就已经存储到数组最右边的结点中了。
3、第二轮排序则是从第一个元素到倒数第三个元素依次与其右边的元素进行比较,如果左边的元素大于右边的元素,那么两个元素就互换。
4、依照此方式,一直到只有第一和第二个元素互相比较而结束。
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {89,34,-270,17,3,100};
System. out.print("排序前数组:" );
printArray(arr);
bubbleSort(arr);
System. out.print("排序后数组:" );
printArray(arr);
}
public static void bubbleSort(int[] arr){
for(int x = 0; x < arr.length - 1; x++){
for(int y = 0; y < arr.length - 1 -x; y++){
if(arr[y] > arr[y+1]){
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
public static void printArray(int[] arr){
System. out.print("[" );
for(int x = 0; x < arr.length; x++){
if(x != arr.length - 1)
System. out.print(arr[x] + "," );
else
System. out.println(arr[x] + "]" );
}
}
}
3.折半查找
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {4,1,5,7,8,4,2};
int index = getIndex(arr,2);
System. out.println("index = " + index);
}
public static int getIndex(int[] arr, int key){
for(int x = 0; x < arr.length; x++){
if(arr[x] == key)
return x;
}
return -1;
}
}
注意:
如果一个数组是无序的,那么可以通过简单遍历查找的方式查找到某个元素所在的角标。
但是如果一个数组是有序的,那么就可以通过一种更高效的方式达到相同的目的,也就是二分查找。
思路:
1、设置三个变量记录角标:min、max、mid。min初始值为0,max为数组最大角标,mid为(max+min)/2。
2、查看mid角标的元素是否与待查找的值相等,如果相等,则直接返回角标值,程序终止执行。
3、如果待查找的值小于角标为mid的元素值,那么说明待查找的元素的位置可能在min与mid角标之间。设置max = mid - 1,mid = (max + min)/2,重复第1、2步的操作。
4、如果待查找的值大于角标为mid的元素值,那么说明待查找的元素的位置可能在mid与max角标之间。设置min = mid + 1,mid = (max + min)/2,重复第1、2步的操作。
5、如果数组中不存在待查找的元素,那么按照如上流程,最终min角标值会大于max角标值,此时返回-1。
具体流程如下图所示:
代码1:
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {13,15,19,28,33,45,78,106};
int index = binarySearch(arr,78);
System. out.println("index = " + index);
}
public static int binarySearch(int[] arr, int key){
int max,min,mid;
min = 0;
max =arr. length - 1;
mid = (max + min)/2;
while(arr[mid] !=key){
if(key > arr[mid])
min = mid + 1;
else if (key < arr[mid])
max = mid - 1;
if(max < min)
return -1;
mid = (max + min)/2;
}
return mid;
}
}
代码2:
class ArrayDemo{
public static void main(String[] args) {
int[] arr= {13,15,19,28,33,45,78,106};
int index = binarySearch(arr,78);
System. out.println("index = " + index);
}
public static int binarySearch(int[] arr, int key){
int max,min,mid;
min = 0;
max = arr. length - 1;
while(min <= max){
mid = (max + min) >> 1;
if(key > arr[mid])
min = mid + 1;
else if (key < arr[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
}
2-8-5 数组中的数组
二维数组[][]格式1:
int[][] arr = new int[3][2];
定义了名称为arr的二维数组,二维数组中有3个一维数组,每一个一维数组中有2个元素,一维数组的名称分别为arr[0], arr[1], arr[2]。
给第一个一维数组1脚标位赋值为78写法是:arr[0][1] = 78;。
其中arr存储的是二维数组的初始地址,arr[0]、arr[1]、arr[2]存储的是一维数组的初始地址。
格式1:
格式2:
int[][] arr = new int[3][];
二维数组中有3个一维数组,每个一维数组都是默认初始化值null,可以对这个三个一维数组分别进行初始化。
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
内存分布图如下:
格式3:
int[][] arr = {{3,8,2},{2,7},{9,0,1,6}};
定义一个名称为arr的二维数组,二维数组中的有三个一维数组,每一个一维数组中具体元素也都已初始化。
第一个一维数组 arr[0] = {3,8,2};,第二个一维数组 arr[1] = {2,7};,第三个一维数组 arr[2] = {9,0,1,6};。
第三个一维数组的长度表示方式:arr[2].length;。
应用:求二维数组所有元素的和
class Array2Demo
{
public static void main(String[] args){
int sum = 0;
int[][] arr = {{3,1,7},{5,8,2,9},{4,1}};
for(int x = 0; x < arr.length; x++){
for(int y = 0; y < arr[x].length; y++){
sum += arr[x][y];
}
}
System. out.println("sum = " + sum);
}
}