java中lifo的数组_03_Java数组与方法_02

经过前面一、二维数组的练习后不难发现,想要提高数组的维数,只要在声明数组的时候将索引与中括号再加一组即可,所以三维数组的声明为int A[][][],而四维数组为int A[][][][] ……,以此类推。

使用多维数组时,输入、输出的方式和一、二维相同,但是每多一维,嵌套循环的层数就必须多一层,所以维数越高的数组其复杂度也就越高。以三维数组为例,在声明数组时即赋初值,再将其元素值输出并计算总和。

范例:TestJava3_7.java

//下面程序说明了三维数组的使用方法,要输出数组的内容需要采用三重循环

public classTestJava3_7

{public static voidmain(String args[])

{int sum=0;int A[][][] ={

{{5,1}, {6,7}},

{{9,4}, {8,3}}

};//声明数组并设置初值//三维数组的输出需要采用三层for循环方式输出

for(int i = 0; i < A.length; i++) //输出数组内容并计算总和{for(int j = 0; j < A[i].length; j++)

{for(int k = 0; k < A[i][j].length; k++)

{

System.out.println("A["+i+"]["+j+"]["+k+"]=" +A[i][j][k]);

sum+=A[i][j][k];

}

}

}

System.out.println("sum="+sum);

}

}

输出结果:

A[0][0][0]=5

A[0][0][1]=1

A[0][1][0]=6

A[0][1][1]=7

A[1][0][0]=9

A[1][0][1]=4

A[1][1][0]=8

A[1][1][1]=3

sum=43

由于使用的是三维数组,所以嵌套循环有三层。如果利用for_each遍历,则如下:

for(int[][] i : A)

{for(int[] j : i)

{for(intiVal : j)

{

System.out.println(iVal);

sum+=iVal;

}

}

}

3.4 引用类型数组

对象数组概念应用几乎与数组一致,不同的是,对象数组是一组相同类型对象而组成的集合,因此初始化时,对象的默认值是null。

与基本数据类型数组一样,对象数组的声明和初始化采取的方法类似,如下:

类名称[] 对象数组名称 = new 类名称[对象个数]

使用方法与基本数据类型数组类似。例如:要取得对象数组的长度也是使用对象数组名称.length。

3.5 浅拷贝与深拷贝

浅拷贝是直接定义一个新的数组变量等于原始数组变量。

实例如下:

int a[] = {1, 2, 3, 4};int b[] =a;

b[3] = 9;for(intiVal : a)

System.out.println(iVal);

此时输出数组a的所有元素,发现a[3]也变为了9。因为b和a指向同一个内存空间。这种数组赋值方式称为浅拷贝。

在一维数组中,我们介绍了System类的arraycopy可以实现将一维数组的所有元素拷贝到另一个一维数组中,相当于是将数据“克隆”了一份,而不是复制一个变量,让两个变量来引用同一个数组,保存数据的独立性。这就是深拷贝。

实例如下:

int a[] = {1, 2, 3, 4};int b[] = new int[4];

System.arraycopy(a,0, b, 0, b.length);

b[3] = 9;for(intiVal : a)

System.out.println(iVal);

此时输出数组a的所有元素,发现a[3]仍为4。因为b和a指向不同的堆空间。这种数组赋值的方式称为深拷贝。

如果是二维数组,则示例如下:

public classTestJava

{public static voidmain(String[] args) {int[][] source = new int[5][]; //定义源数组//给源数组赋值

for (int i = 0; i < 5; i++)

{

source[i]= new int[i + 1];for (int j = 0; j < source[i].length; j++)

source[i][j]= j + 1;

}//打印源数组的数据System.out.println("-------------源数据-------------");for (int i = 0; i < source.length; i++)

{for (int j = 0; j < source[i].length; j++)

System.out.print(source[i][j]+ " ");

System.out.println();

}//定义目的数组

int[][] target1 = source;//浅拷贝//如果只拷贝一维,也是浅拷贝//int[][] target1 = new int[5][];//System.arraycopy(source, 0, target1, 0, source.length);//改变目的1数组的值target1[1][0] = 100;//打印源数组的信息,可以看到值改变,说明没有深拷贝System.out.println("-----------浅拷贝后输出-----------");for (int i = 0; i < source.length; i++)

{for (int j = 0; j < source[i].length; j++)

System.out.print(source[i][j]+ " ");

System.out.println();

}int[][] target2 = new int[5][];//数组的深拷贝,先拷贝"第一维"的System.arraycopy(source,0, target2, 0, source.length);//再深拷贝

for (int i = 0; i < 5; i++)

{

target2[i]= new int[i + 1];

System.arraycopy(source[i],0, target2[i], 0, i + 1);

}//改变目的2数组的数据target2[1][0] = 999;//打印源数组的信息,可以看到值没有改变,说明是深拷贝System.out.println("-----------深拷贝后输出未把100改成999-----------");for (int i = 0; i < source.length; i++)

{for (int j = 0; j < source[i].length; j++)

System.out.print(source[i][j]+ " ");

System.out.println();

}

}

}

3.6 方法

方法可以简化程序的结构,也可以节省编写相同程序代码的时间,达到程序模块化的目的。在每一个类里出现的main()即是一个方法。使用方法来编写程序代码有相当多的好处,它可简化程序代码、精简重复的程序流程,并把具有特定功能的程序代码独立出来,使程序的维护成本降低。

在面向对象的世界里,方法只能作为类和对象的附属,不能独立定义,只能在类里面定义。方法要么属于一个类,要么属于一个对象。方法不能独立执行,执行方法必须使用类或者对象作为调用者。

方法分为两种:

普通方法(对象的方法):没有static关键字修饰的方法

静态方法(类的方法):使用static关键字修饰的方法

方法的定义格式:

5922a4f67805bace58895ce4d01a6cd7.png

方法名称规则:第一个单词的字母小写,以后每个单词的首字母大写。如果不需要传递参数到方法中,只要将括号写出,不必填入任何内容。此外,如果方法没有返回值,则返回值类型要指明为void,return语句可以省略或写成“return;”。

类中方法的定义示例如下:

8409154d00ba9341a3ef3681ebeda0d4.png

类中方法的调用:

普通方法(对象的方法):通过类的实例化对象来调用

静态方法(类的方法):通过类来调用

760f73c5e7f63783adcfaf9b574b072c.png

3.6.1 方法操作的简单范例

TestJava3_8是一个简单的方法操作范例,它在显示器上先输出19个星号“*”,换行之后再输出“I Like Java!”这一字符串,最后再输出19个星号。

范例:TestJava3_8.java

//以下程序主要说明如何去声明并使用一个方法

public classTestJava3_8

{public static voidmain(String args[])

{

star();//调用star() 方法System.out.println("I Like Java !");

star();//调用star() 方法}public static void star() //star() 方法{for(int i=0;i<19;i++)

System.out.print("*"); //输出19个星号System.out.print("\n"); //换行}

}

输出结果:

*******************

I Like Java !

*******************

TestJava3_8中声明了两个方法,分别为main()方法与star()方法。因为main()方法是程序进入的起点,所以把调用star()的程序代码编写在main()里。在main()的第6行调用start() 方法,此时程序的运行流程便会进到10~15行的star()方法里执行。执行完毕后,程序返回main()方法,继续运行第7行,输出“I Like Java !”字符串。接着第8行又调用sart()方法,程序再度进到第10~15行的star()方法里运行。运行完后,返回main()方法里,因main()方法接下来已经没有程序代码可供执行,于是结束程序TestJava3_8。

从本程序中,可以很清楚地看出,当调用方法时,程序会跳到被调用的方法里去运行,结束后则返回原调用处继续运行。在TestJava3_8中,调用与运行star()方法的流程如图3-6所示:

9a32d1f1e9bca3e305ae45365da779dd.png

图3-6  调用与运行star()方法的流程

star()方法并没有任何返回值,所以star()方法前面加上了一个void关键字。此外,因为star()没有传递任何的参数,所以star()方法的括号内保留空白即可。

至于在star()方法之前要加上static关键字,这是因为main()方法本身也声明成static,而在static方法内只能访问到static成员变量(包括数据成员和方法成员),因star()方法被main()方法所调用,自然也要把star()声明成static才行。此时如果还不了解static的真正用意也没有关系,将在以后的章节对static关键字做详尽的介绍。

3.6.2 方法的参数传递与返回值

如果方法有返回值,则在声明方法之前就必须指定返回值的数据类型。相同的,如果有参数要传递到方法内,则在方法的括号内必须填上该参数及其类型。

TestJava3_9是一个关于计算长方形对角线长度的范例,其中show_length()方法可接收长方形的宽与高,计算后返回对角线的长度。

范例:TestJava3_9.java

//以下的程序说明了方法的使用

public classTestJava3_9

{public static voidmain(String args[])

{doublenum;

num=show_length(22, 19); //输入22与19两个参数到show_length()里

System.out.println("对角线长度= "+num);

}public static double show_length(int m, intn)

{return Math.sqrt(m*m + n*n); //返回对角线长度

}

}

输出结果:

对角线长度= 29.068883707497267

TestJava3_9的第7行调用show_length(22,19),把整数22和19传入show_length()方法中。第12行则利用Math类里的sqrt()方法计算对角线长度。而sqrt(n)的作用是将参数n开根号。因sqrt()的返回值是double类型,因此show_length()返回值也是double类型。

Java中参数传递实质是值传递。Java中进行赋值操作或函数调用中传递参数时,遵循值传递的原则:

基本类型数据传递的是该数据的值本身

引用类型数据传递的是对对象的引用(句柄),而非对象本身

只有引用类型数据传递方式才能将数据写回(传出)。

范例:TestJava3_10.java

public classTestJava3_10

{public static voidmain(String[] args)

{int x = 10;int y = 20;

System.out.println("main:x="+x+"\ty="+y);

swith(x, y);

System.out.println("main:x="+x+"\ty="+y);int arr[] = {10, 20};

System.out.println("main:x=" + arr[0] + "\ty=" + arr[1]);

change(arr);

System.out.println("main:x=" + arr[0] + "\ty=" + arr[1]);

}public static void swith(int x, inty)

{

x=x+y;

y=x-y;

x=x-y;

System.out.println("swith:x="+x+"\ty="+y);

}public static void change(inta[])

{

a[0] = (a[0] + a[1]) - (a[1] = a[0]);

System.out.println("change:x="+a[0]+"\ty="+a[1]);

}

}

3.6.3 将数组传递到方法里

方法不只可以用来传递一般的变量,也可用来传递数组。本节将讲述在Java里是如何传递数组以及如何处理方法的返回值是一维数组的问题。

3.6.3.1 传递一维数组

要传递一维数组到方法里,只要指明传入的参数是一个数组即可。TestJava3_11是传递一维数组到largest()方法的一个范例,当largest()接收到此数组时,便会把数组的最大值输出。

范例:TestJava3_11.java

//一维数组作为参数来传递,这里的一维数组采用静态方式赋值

public classTestJava3_11

{public static voidmain(String args[])

{int score[] = {7, 3, 8, 19, 6, 22}; //声明一个一维数组score//将一维数组score传入largest()方法中,并将最大值返回来System.out.println("最大的数= " +largest(score));

}public static int largest(intarr[])

{int tmp = arr[0];for(int i=0; i

tmp=arr[i];returntmp;

}

}

输出结果:

最大的数= 22

TestJava3_11的第10~17行声明largest()方法,并将一维数组作为该方法的参数。第12~16行找出数组的最大值,并将它返回。注意如果要传递数组到方法里,只要在方法内填上数组的名称即可,如本题的第8行所示。

3.6.3.2 传递二维数组

二维数组的传递与一维数组相当类似,只要在方法里声明传入的参数是一个二维数组即可。程序TestJava3_12是有关传递二维数组的一个范例,把二维数组A传递到print_mat()方法里,并在print_mat()方法里把该数组值输出。

范例:TestJava3_12.java

//以下程序说明了如何将一个二维数组作为参数传递到方法中

public classTestJava3_12

{public static voidmain(String args[])

{int A[][]={{51,38,22,12,34}, {72,64,19,31}}; //定义一个二维数组Aprint_mat(A);

}public static void print_mat(int arr[][]) //接收整数类型的二维数组{for(int i=0; i

{for(int j=0; j

System.out.print(arr[i][j]+" "); //输出数组值System.out.print("\n"); //换行}

}

}

输出结果:

51 38 22 12 34

72 64 19 31

TestJava3_12的第9~17行声明了print_mat()方法,它可接收二维数组,并利用两个for循环把数组的值输出来。注意可以利用.length取出数组的行数或列数,如程序的第11与13行所示。

3.6.3.3 返回数组的方法

如果方法返回整数,则必须在声明时在方法的前面加上int关键字。相反的如果返回的是一维的整型数组,则必须在方法的前面加上int[]。若是返回二维的整型数组,则加上int[][],以此类推。

TestJava3_13.java是返回二维数组的一个范例。将一个二维数组传入addTen()方法中,在addTen()方法内将每一个元素加10之后返回它,最后在main()里输出此数组。

范例:TestJava3_13.java

//以下的程序说明了方法中返回一个二维数组的实现过程

public classTestJava3_13

{public static voidmain(String args[])

{int A[][] = {{51,38,82,12,34}, {72,64,19,31}}; //定义二维数组

int B[][] = new int[2][5];

B= addTen(A); //调用addTen(),并把返回的值设给数组B

for(int i=0; i

System.out.print(B[i][j]+" ");

System.out.print("\n");

}

}public static int[][] addTen(intarr[][])

{for(int i=0;i

arr[i][j]+= 10; //将数组元素加10

return arr; //返回二维数组}

}

输出结果:

61 48 92 22 44

82 74 29 41

第16行赋值addTen()是可接收二维数组,且返回类型是二维的整型数组。第20行是完成了在循环内将数组元素值加10的操作,而运算之后的结果再由第21行的return语句返回。

3.6.4 方法的重载

方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或参数类型不同即可。在这种情况下,该方法就叫被重载了。举例如下:

老板指派采购员买东西,当老板没有指明买什么时,采购员可能默认买地瓜;

如老板指明要采购员买大米,采购员可能到最近的超市买10斤大米;

如老板指明采购员今天晚上到龙华宜家超市买5斤大米,那采购员将不得不按老板指定的时间、地点去购买5斤大米。如图3-8所示:

d38fcf36e76b057384c5cf858cc0db74.png

图3-7  采购食材

方法的重载:方法名相同,参数不同(参数个数、参数类型、参数顺序)。仅仅依靠方法的返回值不同,不能构成方法的重载。

范例:TestJava3_14.java

//以下程序说明了方法的重载操作

public classTestJava3_14

{public static voidmain(String[] args)

{intint_sum;doubledouble_sum ;

int_sum= add(3, 5); //调用有两个参数的add方法System.out.println("int_sum = add(3, 5)的值是:"+int_sum);

int_sum= add(3, 5, 6); //调用有三个参数的add方法System.out.println("int_sum = add(3, 5, 6)的值是:"+int_sum);

double_sum= add(3.2, 6.5); //传入的数值为doule类型System.out.println("double_sum = add(3.2, 6.5)的值是:"+double_sum);

double_sum= add(3.2, 6);//传入的前一个是double,后一个是intSystem.out.println("double_sum = add(3.2, 6)的值是:"+double_sum);

double_sum= add(3, 6.5);//传入的前一个是int,后一个是doubleSystem.out.println("double_sum = add(3, 6.5)的值是:"+double_sum);

}public static int add(int x, inty)

{return x +y;

}public static int add(int x, int y, intz)

{return x + y +z;

}public static double add(double x, doubley)

{return x +y;

}public static double add(double x, inty)

{return x +y;

}public static double add(int x, doubley)

{return x +y;

}

}

输出结果:

int_sum = add(3, 5)的值是:8

int_sum = add(3, 5, 6)的值是:14

double_sum = add(3.2, 6.5)的值是:9.7

double_sum = add(3.2, 6)的值是:9.2

double_sum = add(3, 6.5)的值是:9.5

可以发现上题中的add被重载了五次,但每个重载了的方法所能接受参数的个数或类型或顺序不同,相信大家现在应该可以明白方法重载的概念了。那么为什么要用方法重载?

我们知道,在现实中,往往一个类会实现复杂的功能,其中定义的多种方法可能实现的功能意义都是一样,比如我们已经熟悉的System类中的静态方法println(),在该类中println()被定义了多个,每一个方法都有不同的参数,现在我们已知道每一个println()都具有相同的功能:在控制台上输出内容!

我们来假想一下,如果按照每个方法定义一个不同名称,那么我们将在System类中定义十多种不同名称的打印方法,虽然功能实现了,首先,我们是否需要编写代码前给这十几种方法取不同名称,并且还得保证名称唯一,这就会增加我们的工作量;其次我们还得记住每一个方法名对应的功能,如果稍有记错,那就会得到错误的结果!因此,我们有更好的解决办法,通过重载,可以在一个类中定义相同名称、不同参数的实现相同功能的多个方法,这样就避免了给每个方法取不同名称、熟记每个不同名的方法对应的功能的额外工作量,提高了我们的开发效率。

3.6.5 方法的参数可变

从JDK1.5以后,Java允许定义方法的参数长度可变,从而允许为方法指定数量不确定的形参,如果在定义方法时,在最后一个参数的类型后增加三点(…),则表明该形参可以接受多个参数值,参数可变被当成数组传入。

范例:TestJava3_15.java

//以下程序说明了方法的参数可变

public classTestJava3_15

{public static voidmain(String[] args)

{int[] arr={1, 34, 4, 3, 6, 36};

add1(1, 34, 4, 3, 6, 36);

add1(1, 9, 10, 22, 77);

add1(1, 9, 10);

add2(arr);

}public static void add1(int... y)

{int iSum = 0;for(inti : y)

{

iSum+=i;

}

System.out.println("total:" +iSum);

iSum= 0;for(int i = 0; i < y.length; i++)

iSum+=y[i];

System.out.println("total:" +iSum);

}public static void add2(int[] y)

{int iSum=0;for(inti : y)

{

iSum+=i;

}

System.out.println("total:" +iSum);

iSum= 0;for(int i = 0; i < y.length; i++)

iSum+=y[i];

System.out.println("total:" +iSum);

}

}

需要注意的是,不能同时出现add(int…)和add(int [])的形式。

3.6.6 递归

一个方法调用自己的过程称为递归调用。

递归方法的运行实现原理:

我们发现,递归就是一个不停调用方法自身的一个过程,即方法的反复调用!计算机是通过栈的机制来实现方法调用的。首先,我们来了解下计算机的方法调用机制:

1.程序执行前,计算机会在内存中创建一个调用栈 ,一般会比较大;

2.当调用某个方法时,会有一个和该被调用方法相关的记录信息被推入到栈中;

3.被推入到栈中的记录信息包括内容:传递到被调用方法中的参数值、该方法的局部变量、该方法的返回值。

4. 当返回某个方法或者方法结束时,会从栈中取出对应的方法记录信息。

5. 栈的使用机制:后进先出(LIFO)。

注意:虽然递归方法简洁,但是效率不是完全就比循环高,有时甚至低。因为我们考虑算法不仅要从时间、增长率来考虑,还要考虑空间(一般指内存)问题,递归的栈空间是我们必须考虑的,因为每次方法的调用都需额外的空间来存储相关信息。

构造递归方法的关键在于寻找递归算法和终结条件。例如:求n的阶乘:

n! = n*(n-1)*(n-2)*(n-3)…*2*1 = n*(n-1)!//递归算法

1! = 1//终结条件

计算n!必须算出(n-1)!,计算(n-1)!必须计算出(n-2)!...由此推到1!=1。可以归纳阶乘的递归算法如下:f(n) = n * f(n-1);   结束条件:f(1) = 1。

范例:TestJava3_16.java

import java.util.*;public classTestJava3_16

{public static voidmain(String args[])

{

System.out.print("请输入一个正整数:");

Scanner scan= newScanner(System.in);int iNum =scan.nextInt();

System.out.println(iNum+ "!=" +factorial(iNum));

}public static int factorial(intnum)

{/** 利用非递归实现

* int iRet = 1;

* for(int i = 1; i <= num; i++)

*iRet *= i;

* return iRet;*/

//利用递归实现

if(num == 1)return 1;return num * factorial(num-1);

}

}

注意事项:

递归容易造成死循环,所以一定要注意退出条件。

·本章摘要:

1、数组是由一组相同类型的变量所组成的数据类型,它们是以一个共同的名称来表示的。数组按存放元素的复杂程度,分为一维、二维及多维数组。

2、使用Java中的数组,必须经过两个步骤:(1)声明数组、(2)开辟内存给该数组。

3、在Java中欲取得数组的长度(也就是数组元素的个数),可以利用.length 来完成。

4、如果想在声明时就给数组赋初值,只要在数组的声明格式后面加上初值的赋值即可。

5、Java允许二维数组中每行的元素个数均不相同。

6、在二维数组中,若是想取得整个数组的行数,或是某行元素的个数时,也可以利用.length 来获取。

7、方法的重载:在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或类型不同即可。在这种情况下,该方法就叫被重载了,这个过程称为方法的重载。

8、方法的参数可变:当作数组处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值