知识点:
1.数组的基本作用与定义语法;
2.二维数组的使用;
3.数组方法的相互操作;
4.与数组有关的类库方法使用;
5.对象数组;
具体内容:
在具体的开发中,数组是一个非常重要的概念,所有的项目都使用数组。
数组的基本概念:
数组指的是一组相关变量的集合。
数组的定义语法如下:
声明并开辟数组:数据类型 数组名称 [ ] = new 数据类型 [ 长度 ],此方式比较多。
数据类型 [ ] 数组名称 = new 数据类型 [ 长度 ];
分布完成:
——声明数组:数组类型 数组名称 [ ] = null,数组属于引用类型,引用类型默认值为Null。
——开辟数组:数组名称 = new 数据类型 [长度]。
当数组开辟之后可以采用“数组名称[下标|索引]”的形式进行访问。注意所有数组的下标都是从0开始的。即:如果是3个长度的数组,那么洗标的范围:0~2(0,1,2一共三个内容)。如果访问数组操作了数组的允许下标的长度,那么就会出现数组越界的异常(ArrayIndexOutOfBoundsException)。
以上给出的数组定义结构使用的是动态初始化的方式。即:数组首先开辟内存空间,但是数组的内容都是其对应数据类型的默认值。
由于数组是一种顺序的结构,并且数组的长度都是固定的,那么可以使用循环的方式输出,很明显需要知道for循环,而且在java里面为了方便数组的输出提供了一个“数组名称.length”的属性,可以取得数组长度。
范例:定义数组
package 数组;
public class ArrayDemo {
public static void main(String args[]){
//声明并且开辟一个3个长度的数组
int data [] = new int [3];
data[0] = 10;
data[1] = 20;
data[2] = 30;
for(int x=0;x<data.length;x++){
System.out.println(data[x]);
}
}
}
虽然数组的操作比较简单,但是最麻烦的问题在于,它也属于引用数据类型,所以以上的代码依然需要牵扯到内存分配;对象堆内存保存的是属性,而数组中的堆内存保存的是一组信息。
以上使用的是第一种数组定义的语法,下面是第二种:
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = null; //声明数组
data = new int [3]; //开辟数组空间
data[0] = 10;
data[1] = 20;
data[2] = 30;
for(int x=0;x<data.length;x++){
System.out.println(data[x]);
}
}
}
下面还是以内存关系来描述以上的关系:
既然数组属于引用数据类型,那么数组一定可以发生引用传递。引用传递本质上就是同一块堆内存空间可以被不同的栈访问。
范例:数组的引用传递
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = null; //声明数组
data = new int [3]; //开辟数组空间
data[0] = 10;
data[1] = 20;
data[2] = 30;
int temp [] = data;
temp [0] = 99;
for(int x=0;x<data.length;x++){
System.out.println(data[x]);
}
}
}
以上的数组定义格式严格来讲是属于动态初始化,它的操作特点:先开辟数组空间,而后对数组中的内容进行赋值。在数组中还提供有静态初始化的操作,即:数组定义的同时就设置号了相应的数据内容,格式如下:
格式一,简化格式:
数据类型 数组名称 [ ] = {值,值,值.......};
格式二,完整格式:
数据类型 数组名称 [ ] = new 数据类型 [ ] {值,值,值.....};
范例:数组的静态初始化:
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int [] {1,2,3,4,5};
for(int x=0;x<data.length;x++){
System.out.println(data[x]);
}
}
}
在实际的工作中,数组是会存在的,但是它的内容大部分情况下都是通过传递的数据而同台生成的,很少出现先开辟数组而后去使用的情况。
虽然数组支持顺序的数据访问操作,但是数据有一个大的缺点——长度固定不能被改变。故此会应用数组的该概念,不会应用数组。就是保存多个变量。
二维数组(了解):
在之前数组里面只有一个[ ],所以此类数组就是一个普通的数组,或者麻烦一遍称之为一维数组。如果要想描述更多的数据可以使用二维数组,后面有两个中括号[ ] [ ]。
一维数据严格来讲就是一行,类似于如下形式:
索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
数据 | 90 | 20 | 13 | 45 | 26 | 35 | 45 | 456 | 41 |
如果在一维数组里面要找到一个数据,只需要找到一个确定的索引就够了
二维数据就是一张表,有行有列,类似于如下形式:
索引 | 列:0 | 列:1 | 列:2 | 列:3 | 列:4 | 列:5 | 列:6 | 列:7 | 列:8 |
行:0 | 90 | 20 | 13 | 45 | 26 | 35 | 45 | 456 | 41 |
行:1 | 12 | 212 | 16 | 45 | 32 | 7 | 54 | 6 | 5 |
行:2 | 45 | 2 | 33 | 2 | 65 | 56 | 5 | 5 | 47 |
需要行和列确定一个数据,如:7的索引位置:行1列5,”[1][5]“
定义语法:
动态初始化: 数据类型 数组名称 [ ] [ ] = new 数据类型[ 行的个数] [ 列的个数]
静态初始化: 数据类型 数据名称 [ ] [ ] = new 数据类型 [ ] [ ] {{值,值,值},{值,值,值}.......}
通过定义的结构发现,所谓的二维数组实际上就是将一个一维数据变为了一个大的数组,并且为每一个一维数组设置了一个行号而已。
范例:观察二维数组
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [][] = new int [][] {
{1,2,3},
{4,5,6},
{7,8,9}
};
//外层循环是控制数组的数据行内容的
for(int x=0;x<data.length;x++){
//内层循环是控制数组的数据列内容
for(int y=0;y<data[x].length;y++){
System.out.print(data[x][y]+"\t");
}
System.out.println();
}
}
}
随着开发的发展,直接编写的代码很少出现二维数组的概念。
数组与方法参数的传递(难点):
引用传递除了基本数据类型,也可以传递数组。如果传递的数组,要注意内存分配图。
范例:数组传递程序
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int [] {1,2,3,4};
change(data);
for(int x=0;x<data.length;x++){
System.out.print(data[x]+"\t");
}
}
//此方法定义在主类中,并且由主方法直接调用,所以关键字就直接用public static
public static void change(int temp []){
for(int x=0;x<temp.length;x++){
temp[x]*=2; //将数组的内容乘2保存
}
}
}
修改代码
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int [] {1,2,3,4};
int temp [] =data;
for(int x=0;x<temp.length;x++){
temp[x]*=2;
}
for(int x=0;x<data.length;x++){
System.out.println(data[x]);
}
}
}
在进行数组的引用传递的过程中,方法对数组的修改一定会影响到原始数据。
范例:实现一个数组排序(数组的排序操作在笔试之中经常被问到,下面给出(升序)排序原理)
原始数据:2,1,9,0,5,3,7,6,8;
基础实现:
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int []{2,1,9,0,5,3,7,6,8};
print(data);
//外层控制排总体的次数
for(int x=0;x<data.length-1;x++){
for(int y=0;y<data.length-1;y++){
if(data[y]>data[y+1]){
int t = data[y];
data[y] = data[y+1];
data[y+1] = t;
}
}
}
print(data);
}
//专门定义一个输出的功能的方法
public static void print(int temp []){
for(int x=0;x<temp.length;x++){
System.out.print(temp[x]+"、");
}
System.out.println();
}
}
改善设计:主方法设计上是作为程序的起点存在,那么所有的程序的起点都可以称为客户端。既然是客户端所有调用的代码编写一定要简单,可以采用方法进行封装。
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int []{2,1,9,0,5,3,7,6,8};
sort(data);
print(data);
}
public static void sort(int arr[]){
//外层控制排总体的次数
for(int x=0;x<arr.length-1;x++){
for(int y=0;y<arr.length-1;y++){
if(arr[y]>arr[y+1]){
int t = arr[y];
arr[y] = arr[y+1];
arr[y+1] = t;
}
}
}
}
public static void print(int temp [] ){
for(int x=0;x<temp.length;x++){
System.out.print(temp[x]+"、");
}
}
}
面试题:请编写一个数组排序操作,答案如上。
范例:实现数组的转置(首位交换)
原始数据:1,2,3,4,5,6,7,8,9,
转置后的数组:9,8,7,6,5,4,3,2,1
如果想要实现转置操作,两个思路:
1.定义一个新的数组,而后将原始数组按照倒序的方式插入到先的数组之中,随后改变原始数组引用;
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int []{2,1,9,0,5,3,7,6,8,9};
//首先定义一个信的数组,长度与原始长度一致
int foot = data.length-1;
int temp [] = new int [data.length];
for(int x=0;x<temp.length;x++){
temp[x]=data[foot--];
}
print(data);
data=temp;
print(data);
}
public static void print(int data [] ){
for(int x=0;x<data.length;x++){
System.out.print(data[x]+"、");
}
System.out.println();
}
}
虽然以上的代码实现了转置的操作,但是遗憾的是,代码里面会产生垃圾。
2.利用算法,在一个数组上完成转置操作;
原始数据:1,2,3,4,5,6,7,8,9
第一次转置:9,2,3,4,5,6,7,8,1
第二次转置:9,8,3,4,5,6,7,2,1
第三次转置:9,8,7,4,5,6,3,2,1
................
转换次数:无论是原始数据是奇数还是偶数,数组的长度除以二;
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int []{1,2,3,4,5,6,7,8,9};
reverse(data);
print(data);
}
//此方法专门实现数组的转置操作
public static void reverse(int arr[]){
int len = arr.length/2; //转置次数
int head = 0; //头部索引
int tail = arr.length-1; //尾部
for(int x=0;x<len;x++){
int temp = arr[head];
arr[head] = arr[tail];
arr[tail] =temp;
head++;
tail--;
}
}
//此方法实现一个输出功能
public static void print(int temp [] ){
for(int x=0;x<temp.length;x++){
System.out.print(temp[x]+"、");
}
System.out.println();
}
}
二维数组的转置:
原始数据:1 2 3 第一次转置:1 4 3 第二次转置:1 4 7 第三字转置:1 4 7
4 5 6 2 5 6 2 5 6 2 5 8
7 8 9 7 8 9 3 8 9 3 6 9
只有行和列不同的时候才会发生转置。
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [][] = new int [][]{
{1,2,3,},{4,5,6},{7,8,9}
};
print(data);
reverse(data);
print(data);
}
//此方法专门实现数组的转置操作
public static void reverse(int arr[][]){
for(int x=0;x<arr.length;x++ ){
for(int y=x;y<arr[x].length;y++){
if(x!=y){ //行和列不同进行交换
int temp = arr[x][y];
arr[x][y] = arr[y][x];
arr[y][x] = temp;
}
}
}
}
//此方法实现一个输出功能
public static void print(int temp [][] ){
for(int x=0;x<temp.length;x++){
for(int y=0;y<temp[x].length;y++){
System.out.print(temp[x][y]+"、");
}
System.out.println();
}
System.out.println();
}
}
1 [x=0][y=0] 2 [x=1][y=1] 3 [x=1][y=2]
4 [x=1][y=0] 5 [x=2][y=1] 6 [x=2][y=2]
7 [x=2][y=0] 8 [x=3][y=1] 9 [x=3][y=2]
第一次转换(x=0,y=0,内层循环,即y=0,1,2,循环三次)
- Y的第一次循环,不会改变数据,因为x=y.对应的,代码中if(x!=y){ //行和列不同进行交换
int temp = arr[x][y];
arr[x][y] = arr[y][x];
arr[y][x] = temp;
}
1 [x=0][y=0] 2 [x=1][y=1] 3 [x=1][y=2]
4 [x=1][y=0] 5 [x=2][y=1] 6 [x=2][y=2]
7 [x=2][y=0] 8 [x=3][y=1] 9 [x=3][y=2]
- Y的第二次循环,(x=0,y=1,判断条件满足,进行交换)
1 [x=0][y=0] 4 [x=1][y=0] 3 [x=1][y=2]
2 [x=1][y=1] 5 [x=2][y=1] 6 [x=2][y=2]
7 [x=2][y=0] 8 [x=3][y=1] 9 [x=3][y=2]
- Y的第三次循环,(x=0,y=2,判断条件满足,进行交换)
1 [x=0][y=0] 4 [x=1][y=0] 7 [x=2][y=0]
2 [x=1][y=1] 5 [x=2][y=1] 6 [x=2][y=2]
3 [x=1][y=2] 8 [x=3][y=1] 9 [x=3][y=2]
第二次转换(x=1,y=1,内层循环,即y=1,2,循环两次)
- Y的第一次循环,(x=1,y=1,判断条件不满足,不进行交换)
1 [x=0][y=0] 4 [x=1][y=0] 7 [x=2][y=0]
2 [x=1][y=1] 5 [x=2][y=1] 6 [x=2][y=2]
3 [x=1][y=2] 8 [x=3][y=1] 9 [x=3][y=2]
- Y的第二次循环,(x=1,y=2,满足条件,交换)
1 [x=0][y=0] 4 [x=1][y=0] 7 [x=2][y=0]
2 [x=1][y=1] 5 [x=2][y=1] 8 [x=3][y=1]
3 [x=1][y=2] 6 [x=2][y=2] 9 [x=3][y=2]
第三次转换(x=2,y=2,内层循环,即y=2,循环一次)
- Y的第一次循环(x=2,y=2,不交换)
1 [x=0][y=0] 4 [x=1][y=0] 7 [x=2][y=0]
2 [x=1][y=1] 5 [x=2][y=1] 8 [x=3][y=1]
3 [x=1][y=2] 6 [x=2][y=2] 9 [x=3][y=2]
以上的等行等列矩阵。
以上实现了方法接收数组的操作情况,同样的方法也可以返回数组。
范例:方法返回数组
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = init();//接收数组
print(data);
}
public static int [] init(){ //方法返回数组
return new int [] {1,2,3};
}
public static void print(int temp []){ //输出数组
for(int x=0;x<temp.length;x++){
System.out.print(temp[x]+"、");
}
}
}
数组的操作方法:
java本身针对于数组是有提供类库的支持的。
1.数组拷贝:将一个数组的内容拷贝到另外一个数组之中。
语法:System.arraycopy(源数组名称,源数组拷贝开始索引,目标数组,目标数组拷贝开始索引,长度)
范例:实现数组拷贝
- 数组A:1, 2, 3, 4, 5, 6, 7, 8
- 数组B:11,22,33,44,55,66,77,88
要求拷贝后的数组B:11,22,5,6,7,66,77,88
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int dataA [] = new int []{1,2,3,4,5,6,7,8};
int dataB [] = new int []{11,22,33,44,55,66,77,88};
System.arraycopy(dataA, 4, dataB, 2, 3);
print(dataB);
}
public static void print(int temp []){ //输出数组
for(int x=0;x<temp.length;x++){
System.out.print(temp[x]+"、");
}
}
}
2.数组排序:
语法:java.util.Arrays.sort(数组名称)
范例:实现排序
package 数组;
public class ArrayDemo {
public static void main(String args[]){
int data [] = new int []{3,6,1,8,12,5,7,10};
java.util.Arrays.sort(data);
print(data);
}
public static void print(int temp []){ //输出数组
for(int x=0;x<temp.length;x++){
System.out.print(temp[x]+"、");
}
}
}
3.对象数组(重点)
数组是引用类型,而对象同样也是引用类型,所以如果是对象数组则表示一个引用类型里面嵌套其他的引用类型。在之前使用的数据都属于基本数据类型的数组,但是所有的引用数据类型也同样可以定义数组,这样的数组称之为对象数组。如果想定义对象数组,以类为例,可以采用如下的形式完成:
动态初始化:开辟之后对象数组的内容都是null值,
声明并开辟对象数组:类名称 对象数组名称 [ ] = new 类名称 [ 长度 ]
分布完成:“
声明对象数组:类名称 对象数组名称 [ ] = null;
开辟对象数组:对象数组 = new 类名称 [ 长度 ]
静态初始化:类名称 对象数组名称 = new 类名称 [ ]{实例化对象,实例化对象........};
范例:对象数组动态初始化
package 数组;
class Book{
private String title;
private double price;
public Book(String title,double price){
this.title=title;
this.price=price;
}
public String getInfo(){
return "书名:"+title+",价格"+price;
}
}
public class ArrayDemo {
public static void main(String args[]){
//开辟三个长度的对象数组
Book book [] = new Book [3];
//对象数组中每个数据都需要分别实例化
book[0] = new Book("java",78.9);
book[1] = new Book("jsp",78.9);
book[2] = new Book("Android",98.9);
for(int x=0;x<book.length;x++){
System.out.println(book[x].getInfo());
}
}
}
对象数组实际上就是将对个对象交给数组统一管理。
范例:静态初始化数组
package 数组;
class Book{
private String title;
private double price;
public Book(String title,double price){
this.title=title;
this.price=price;
}
public String getInfo(){
return "书名:"+title+",价格"+price;
}
}
public class ArrayDemo {
public static void main(String args[]){
//开辟三个长度的对象数组
Book book [] = new Book []{
new Book("java",78.9),
new Book("jsp",78.9),
new Book("Android",98.9)
};
for(int x=0;x<book.length;x++){
System.out.println(book[x].getInfo());
}
}
}
一般定义的对象数组都是一维的。
总结:数据用的很少,但是会用,逻辑关系比较麻烦。数组的排序和转置很重要。另外一切以一维数组为主,要明白定义语法与内存关系。最后对象数组的定义语法一定要明确,对象数组 = 对个对象。数组最大的天生短板就是长度固定。数组的排序是java.util.Arrays.sort(数组名称)。