3.6、数组 问题的引出: 例如,现在要求声明100个整型变量,如果按之前的做法:int i1,i2,…..i100,如果按照以上的方式声明,则肯定不方便,所以此时就可以使用数组的概念。 数组:就是一组变量。所有的变量通过下标进行访问。 声明数组的格式: • 数据类型[] 数组名称 = new 数据类型[数组长度] • 数据类型 数组名称[] = new 数据类型[数组长度] • 注意:数组是一种引用的数据类型,在JAVA中只要是引用数据类型,则肯定会牵扯到内存的划分,在数组的声明中有一个new关键字,只要一看到new关键字就意味着要为数组开辟新的内存空间。 例如:以下程序定义了一个数组: public class TestJava09{ public static void main(String args[]){ // 定义一个整型数组 int s[] = new int[10] ; // 数组的访问通过下标完成 s[0] = 10 ; s[2] = 20 ; System.out.println(s[0]) ; System.out.println(s[2]) ; System.out.println(s[3]) ; } }; 从以上代码可以发现,只要是数组如果没有给出具体的值,则肯定就是默认值,整型的默认值:0。 对于数组的访问下标,所有的下标是从0开始的,例如,如果是10个元素的数组,则下标的范围:0~9。如果现在访问了下标10的元素,则会出现以下的错误: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10 数组是引用类型,对于引用类型,则肯定会有堆、栈内存指向关系。 • 栈内存:数组的名字 • 堆内存:存放的是数组的具体内容 • 实际上数组的使用就要划分为两步: |- 声明数组:数据类型 数组名称[] = null ; |- 为数组开辟空间:数组名称 = new 数据类型[长度] ; 既然是引用数据类型,则引用的名称可以有多个。例如:如下的代码: public class TestJava10{ public static void main(String args[]){ // 定义一个整型数组 int s[] = null ; s = new int[10] ; for(int i=0;i<10;i++){ s[i] = 2 * i + 1 ; } // 下面为数组的空间再起一个别名 int temp[] = null ; temp = s ; temp[9] = 100 ; for(int i=0;i<10;i++){ System.out.print(s[i]+"\t") ; } } }; 引用传递:传递的是堆内存的使用权。 以上的数组使用的方式都称为动态初始化,在数组声明的时候并没有固定值,所有的值都是默认的,之后由程序通过下标进行依次的赋值操作,那么对于数组还有另外一种 —— 静态初始化,在数组声明的时候可以直接给出其具体的内容,如下代码所示: public class TestJava11{ public static void main(String args[]){ int s[] = {1,2,3,4,5,6,7,8,9,45,35,6,25,14,124,14,12421,34} ; for(int i=0;i<s.length;i++){ System.out.print(s[i]+"\t") ; } } }; 数组在使用中又有维数的概念,例如,之前的数组声明的时候后面只有一个“[]”,如果是多维的话,则后面会有多个“[]”。 public class TestJava12{ public static void main(String args[]){ int s[][] = new int[3][5] ; s[1][2] = 30 ; s[2][1] = 50 ; for(int i=0;i<s.length;i++){ for(int j=0;j<s[i].length;j++){ System.out.print(s[i][j]+"\t") ; } System.out.println("") ; } } }; 但是,一般的JAVA开发之中数组基本上就使用到一维,多维(二维以上)很少出现。 实际上数组的相关操作比较多:为一个数组排序。 例如:给定一个数组,为其进行由大到小的排序。 public class TestJava13{ public static void main(String args[]){ int s[] = {23,5,3,1,34,54,2,1,1,45,6,7,87,89,0} ; // 要求进行从头到尾的排序 for(int i=0;i<s.length;i++){ for(int j=0;j<s.length-1;j++){ if(s[i]>s[j]){ int temp = s[j] ; s[j] = s[i] ; s[i] = temp ; } } } // 排序之后,对内容进行输出 for(int i=0;i<s.length;i++){ System.out.print(s[i]+"\t") ; } } }; 之前已经学过了方法,那么方法能不能接收一个数组呢? 既然传递的是一个数组,则接收的时候也肯定应该按照一个数组进行接收。 public class TestJava14{ public static void main(String args[]){ int s[] = {23,5,3,1,34,54,2,1,1,45,6,7,87,89,0} ; // 要求进行从头到尾的排序 for(int i=0;i<s.length;i++){ for(int j=0;j<s.length-1;j++){ if(s[i]>s[j]){ int temp = s[j] ; s[j] = s[i] ; s[i] = temp ; } } } printArray(s) ; } public static void printArray(int temp[]){ for(int i=0;i<temp.length;i++){ System.out.print(temp[i]+"\t") ; } } }; 如果想由一个方法返回一个数组,则返回值类型,应该明确的声明返回数组: public class TestJava15{ public static void main(String args[]){ int s[] = init() ; // 要求进行从头到尾的排序 for(int i=0;i<s.length;i++){ for(int j=0;j<s.length-1;j++){ if(s[i]>s[j]){ int temp = s[j] ; s[j] = s[i] ; s[i] = temp ; } } } printArray(s) ; } public static void printArray(int temp[]){ for(int i=0;i<temp.length;i++){ System.out.print(temp[i]+"\t") ; } } public static int[] init(){ int ts[] = {23,5,3,1,34,54,2,1,1,45,6,7,87,89,0} ; return ts ; } }; 既然方法可以接收数组,又可以返回数组,那么能否把上面程序中排序的部分再单独拿出来,做一个方法呢? 数组属于引用传递类型,例如:一个堆内存有两个名称指向,如果一个名称把内容修改了,则其他的名称指向的内容也同时改变。 public class TestJava15{ public static void main(String args[]){ int s[] = init() ; sort(s) ; printArray(s) ; } public static void sort(int t[]){ // 要求进行从头到尾的排序 for(int i=0;i<t.length;i++){ for(int j=0;j<t.length-1;j++){ if(t[i]>t[j]){ int temp = t[j] ; t[j] = t[i] ; t[i] = temp ; } } } } public static void printArray(int temp[]){ for(int i=0;i<temp.length;i++){ System.out.print(temp[i]+"\t") ; } } public static int[] init(){ int ts[] = {23,5,3,1,34,54,2,1,1,45,6,7,87,89,0} ; return ts ; } }; 从整个代码上看,在主方法中编写的代码逐步减少,记:主方法实际上就是一个测试程序的客户端,代码编写的越少越好。 例如:要求设计一个方法,此方法可以完成数组的部分拷贝,例,有两个数组: |- int ar1[] = {1,2,3,4,5,6,7} ; |- int ar2[] = {11,22,33,44,55,66,77,88,99} ; 现在要求此方法可以把ar2中的3~5的元素,拷贝给ar1的1~3的元素,即:拷贝之后ar1的值为: • 1,44,55,66,5,6,7。 如果要完成此操作,则方法需要传递以下参数: • 源数组 • 目标数组 • 源数组的开始点 • 目标数组的开始点 • 拷贝的长度 public class TestJava16{ public static void main(String args[]){ int ar1[] = {1,2,3,4,5,6,7} ; int ar2[] = {11,22,33,44,55,66,77,88,99} ; arrayCopy(ar2,3,ar1,1,3) ; printArray(ar1) ; } public static void arrayCopy(int src[],int start1,int de[],int start2,int len){ for(int i=0;i<len;i++){ de[start2] = src[start1] ; start2++ ; start1++ ; } } public static void printArray(int temp[]){ for(int i=0;i<temp.length;i++){ System.out.print(temp[i]+"\t") ; } } }; 实际上在JAVA中本身已经有很多的API支持,对于数组的排序也有相应的方法完成,例如:如下代码: public class TestJava17{ public static void main(String args[]){ int tem[] = {23,13,13,4,6,7323,13,42,261,36,1,1,16,136531,9} ; java.util.Arrays.sort(tem) ; printArray(tem) ; } public static void printArray(int temp[]){ for(int i=0;i<temp.length;i++){ System.out.print(temp[i]+"\t") ; } } }; 同样,对于之前的数组拷贝操作,也有其自己的操作方法,代码如下: public class TestJava18{ public static void main(String args[]){ int ar1[] = {1,2,3,4,5,6,7} ; int ar2[] = {11,22,33,44,55,66,77,88,99} ; System.arraycopy(ar2,3,ar1,1,3) ; printArray(ar1) ; } public static void printArray(int temp[]){ for(int i=0;i<temp.length;i++){ System.out.print(temp[i]+"\t") ; } } }; 4、总结 1、 JAVA的三种分支及其关系 • JAVA SE、JAVA EE、JAVA ME,三种发展都是以JAVA SE为基础的 2、 执行流程 • *.java javac 编译 *.class java 执行 • java命令属于JVM本身支持的,JAVA在执行的时候会先根据classpath定义好的路径找到类,之后进行加载执行。但是一般classpath都比较习惯于配置在当前所在的文件夹中。 • javac是JDK提供的,如果想使用则要配置path属性。 3、 public class与class声明的区别 • public class:文件名称与类名称一致,一个java文件中只能有一个public class • class:文件名称可以与类名称不一致,一个文件中允许有多个class,编译之后会分成不同的*.class文件保存。 • 类名称编写的时候:所有单词的首字母必须大写 • JAVA的数据类型划分,String 4、 方法及方法的重载 • 方法:就是可重复调用的一段代码段,但是现在所有的方法都是通过main方法直接调用的,所以前面必须加上:public static。 • 方法可以有返回值或者没有,没有的话就直接使用void声明 • 方法重载:方法名称相同,参数的类型或个数不同,称为方法的重载(overload) 5、 数组 • 数组是引用传递类型,必须开辟空间之后才可以使用 • 数组的定义格式:数据类型 数组名称[] = new 数据类型[长度] • 数组有动态和静态两种初始化方法 • 数组的名称保存在栈内存空间,而数组的具体内容保存在堆中 6、 java程序的分类 • applet:主要运行在网页上,没有main方法 • application:主要运行在命令行方式之中,有main方法 |