菜鸡的Java笔记 第七 - java 数组
阅读原文时间:2022年03月10日阅读:1

数组的基本概念     笔试中经常出现的试题或是问题

    1.1 概念
        数组指的是一组相关变量的集合
        如果用最原始的方式定义100个变量的话没问题但是这些变量的关联实在是太麻烦了
    
    在JAVA 中数组属于引用数据类型 既然是引用数据类型就牵扯到内存的关系。
    对于数组的定义语法有以下两种形式
        声明并开辟数组;
            数组类型 数组名称 [] = new 数组类型[长度];
            数组类型 [] 数组名称 = new 数组类型[长度];
        
        分步完成;
            声明数组:    数组类型 数组名称 [] = null;    数组类型 [] 数组名称 = null;
            开辟数组: 数组名称 = new 数据类型 [];
    
    当数组开辟空间之后那么就可以采用“数组[索引]”的形式进行数组的访问
    但是需要注意的是,如果现在数组的长度为3,那么索引的范围是 0~2 (一共3个元素)
    如果操作中超过了数组的允许索引范围,则程序在运行过程之中会出现(数组越界)
    现在是动态初始化 动态初始化的特点 是数组开辟空间之后,数组中每个元素的内容都是其对应数据类型的默认值
    
    数组本身是一种顺序式的结构,所以进行数组内容输出的时候,往往可以采用循环的方式完成
    由于数组的长度是固定的,所以只要是进行数组的输出那么都会考虑使用for循环这里面就牵扯到了一个数组长度的取得,在JAVA中可以使用“数组对象.length”,属性取得
   
//实现数组循环输出

public class array(){ // 程序必须有类
public static void main(String args){
// 定义数组
int data [] = new int[3]; // 开辟了一个data数组,长度为3
Systme .out.println(data.length);
data[0] = 10; // 为数组赋值
data[1] = 20;
data[2] = 30;
for(int x = 0;x<data.length;x++){
// 通过循环来控制索引
Systme.out.println(data[x]+","); //数组名称[索引]
}
}
}

数组引用分析
        引用数据类型的分析过程几乎都是一样的,所以数组的引用分析其本质也是一样的,与对象的流程是相同的
        唯一的区别是在于普通的类对象是把保存属性,利用属性名称来操作,但是数组保存的是一组内容,利用索引来操作
        那么既然此关系可以弄明白 所谓的分步的操作也是就是一样的过程

public class array1(){// 程序必须有累
public static void main(String args[]){
int data[] = new int[3];//开辟了一个data数组,长度为3
// 只有声明的时候加上“[]”
data[0] = 10; // 为数组赋值
data[1] = 20;
data[2] = 30;
int temp [] = data; // 引用
temp[0] = 100; // 引用赋值
System,out,println(data.length);
}
}

数组的静态初始化
        上一课是动态数值的操作讲解,动态初始化操作的特点在于其只能够在开辟数组空间之后进行数组内容的一个赋值
        如果现在希望数组开辟之后就可以存在明确的内容,那么则可以使用数组的静态初始化
        语法如下
            简化型;
                数据类型 数组名称 [] = {值,值,值。。。。。。}
                数据类型 [] 数组名称 = {值,值,值。。。。。。}
            完整型;(推荐使用)
                数据类型 数组名称 [] = new 数据类型[]{值,值,值。。。。。。}
                数据类型 [] 数组名称 = new 数据类型[]{值,值,值。。。。。。}

public class stete(){ // 静态
public static void main(String args[]){
int data[] = new int[]{10,20,30}; // 数组静态初始化
for(int x = 0,x<data.length;x++){
System.out.println(data[x]+"."):
}
}
}

// 范例;判断某一个数字是否在数组中存在?

public class stete(){ // 静态
public static void main(String args[]){
int sdata = 11; // 要查找的数据
boolean flag = false; // 保存查找结果,如果找到了修改为true
int data[] = new int[]{10,20,30,11,22,33}; // 数组静态初始化
for(int x = 0,x<data.length;x++){
if(data[]==sdata){ // 现在已经查找到内容
flag = true;
break; // 退出循环
}
}
if(flag){
System.out.println("该数据已经查找到!"):
}else{
System.out.println("该数据没有查找到!"):
}

}  

}

但是严格来讲现在这个代码性能并不好,因为他需要将数组中的每一个元素都进行判断
    面试题;请解释什么叫二分查找法(折半查找法(log2n))
    二分查找法的重要支持;数组中的数据必须是有序的

     二维数组
        在开发之中,之前使用的数组只有一个索引下标,所以可以简单的将其理解为是一个一维数组。一维数组的特点是可以根据一个索引号确定内容
        二维数组实际上与数据表的形式是完全相同的,有行和列组成,那么想要确认一个数据,必须有行和列的编号
        对于二维数组的定义有两种语法结构;
            动态初始化;
            数据类型 数组名称[][] = new 数据类型[行个数][列个数];
            静态初始化;
            数据类型 数组名称 [][] = new 数据类型[][]{
                {数据,数据,数据……}
                {数据,数据。数据……}
                }
        实际上可以发现二维数组的本质就是在数组里面继续嵌套了其他的数组

public class twoarray(){
public static void main(String args[]){
int data [][] = new int[][]{
{1,2}
{4.5,6}
{7,8,9,10}
};
for(int x = 0;x<data.length;x++){ // 控制数组行
for(int y = 0;y<data[x],length;y++){
System.out.println(data[x][y]+","
)
}
System.out.println():
}
//面试题;实现二维数组转置(转置;行变列,列变行)(这都属于数组的逻辑控制,用于扩充大脑思维)
for(int x = 0;x<data.length;x++){
for(int y = 0;y<=x;y++){
if(x!=y){
int temp = data[x][y];
data[x][y] = data[y][x];
data[y][x] = temp;
}
}
System.out.println():
}
for(int x = 0;x<data.length;x++){ // 控制数组行
for(int y = 0;y<data[x],length;y++){
System.out.println(data[x][y]+","
)
}
System.out.println():
}
System.out.println():
}
}

/* 转置

public class Dtada{
public static void main (String args[]){
intdata [] = new int[]{1,2,3,4,5,6};
reverse(data);
printArray(data);
}
public static void reverse(int temp []){ // 返回数组
int center = temp.length / 2; //计算转换次数
int head = 0;
int tail = temp.length - 1;
for(int y = 0;y<center; y++){
int tempData = temp[head];
temp[head] = temp[tail];
temp[tail] = tempData;
head ++ ;
tail -- ;
}
}
public static void printArray(int temp[]){ //该方法要接收一个
for(int x = 0;x<temp.length; x++){
System.out.println(temp[x] + ",");
}
System.out.println();
}
}

数组与方法
        在数组与方法进行传递的操作过程之中,实际上就是属于引用传递。
        在数组与方法间的操作中主要考虑两种形式方法接收数组,另外一种就是方法返回数组。
        不管是接收还是返回,最终操作的一定是一个堆内存的使用

public class arrayAndMethod{
public static void main(String args[]){
int [] data = new int[]{1,3,5,7,9}: // 数组
printArray(data): // int temp[] = data:
}
public static void printArray(int temp[]){ // 接收一个数组
for(int x = 0:x<temp.length:x++){
System.out.println(temp[x]+"."):
}
System.out.println():// 换行
}
}

//    整个的操作过程与数组的引用接收是完全一样的 但是这个时候的代码只是针对于    当前的数组内容进行了简单的输出。
//    于是下面可以进一步的加强,例如:设置一个方法,在次方法之中实现数据的乘2操作

/*    方法里面修改数组内容

public class arrayAndMethod{  
    public static void main(String args\[\]){  
        int \[\] data = new int\[\]{1,3,5,7,9}: // 数组  
        printArray(data):  // int temp\[\] = data:  
    }  
    public static void inc(int arr\[\]){  // 负责数组内容的改变  
        for(int x = 0:x<arr.length:x++){  
            arr\[x\]\*=2:  //arr\[x\] = arr\[x\]\*2:  //数组中的每个元素乘2后保存  
        }  
    }  
    public static void printArray(int temp\[\]){  // 接收一个数组  
        for(int x = 0:x<temp.length:x++){  
            System.out.println(temp\[x\]+"."):  
        }  
        System.out.println():// 换行  
    }  
}

//    在大部分情况下,如果某一个方法可以接收的数据类型是引用数据类型,那么往往都不需要设置返回值
// setName(String name) 返回的是 void

/*    范例:数据排序操作(理解)
        面对数组中发现可以保存有多个数据,但是在很多时候(例如:二分查找法)
        那么必须针对于数组中的数据进行排序,所以这个时候就需要进行一些复杂的处理

public class arrayAndMethod{  
    public static void main(String args\[\]){  
        int data \[\] = new int\[\]{19,8,37,6,55,4,73,2,91,0}:  
        for(int x = 0:x<data.length - 1:x++){ // 再加一个循环 一次循环是不够的  
            for(int y = 0:y<data.length - 1:y++){ -1 防止越界异常  
                if(data\[y\]>data\[y+1\]){  
                    int temp = data\[y\]:  
                    data\[y\] = data\[y+1\]:  
                    data\[y+1\] = temp:  
                }  
            }  
            System.out,println("第"+ x +"次排序:"):  
            printArray(data):  
        }  
    }  
    public static void printArray(int temp\[\]){  // 接收一个数组  
        for(int x = 0:x<temp.length:x++){  
            System.out.println(temp\[x\]+"."):  
        }  
        System.out.println():// 换行  
    }  
}

分析;
    第1次排序.8.19.6.37.4.55.2.73.0.91
    2.        8.6.19.4.37.2.55.0.73.91
    3        6.8.4.19.2.37.0.55.73.91
    4        6.4.8.2.19.0.37.55.73.91
    5        4.6.2.8.0.19.37.55.73.91
    6        4.2.6.0.8.19…….
    7        2.4.0.6.8.19……
    8        2.0.4.6.8
    9        0.2.4.6.8……
            
    通过分析可以发现 排序并不是一次完成的,而是需要多次,也就是说至少需要“数组长度-1次”    
        
    
    此时是已实现了排序操作的要求。但非常遗憾的是,这个代码里面主方法的代码太多了
    主方法本身就是一个日后程序调用的客户端,所以客户端的操作代码中不应该编写过多的复杂操作,应该将代码进行简化处理

public class arrayAndMethod{  
    public static void main(String args\[\]){  
        int data \[\] = new int\[\]{19,8,37,6,55,4,73,2,91,0}:  
        sort(data):  // 客户端调用越简单越好  
        printArray(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++){ -1 防止越界异常  
                if(arr\[y\]>arr\[y+1\]){  
                    int temp = arr\[y\]:  
                    arr\[y\] = arr\[y+1\]:  
                    arr\[y+1\] = temp:  
                }  
            }  
            System.out,println("第"+ x +"次排序:"):  
            printArray(data):  
        }  
    }  
    public static void printArray(int temp\[\]){  // 接收一个数组  
        for(int x = 0:x<temp.length:x++){  
            System.out.println(temp\[x\]+"."):  
        }  
        System.out.println():// 换行  
    }  
}

面试题请编写一个数组排序操作  (以上就是答案)   

/*    范例:数组的反转操作
        就是将一个数组实现首尾交换,但是交换的实现方式有两种
    第一种实现思路:
        定义一个新的数组,而后将原始数组的内容进行逆序输出。随后改变原始数组的引用

public class arrayAndMethod{  
    public static void main(String args\[\]){  
        int data \[\] = new int\[\]{19,8,37,6,55,4,73,2,91,0}:  
        int newArr\[\] = new int\[data.length\]:  // 声明一个与原始数组大小相同的数组  
        int foot = data.length -1: // 定义原始数组的操作脚标  
        for(int x = 0:x<newArr.length:x++){  
            newArr\[x\] = data\[foot--\]:  // 逆序保存  
        }  
        data = newArr: // 改变原始数组引用  
        printArray(data):  
    }

    public static void printArray(int temp\[\]){  // 接收一个数组  
        for(int x = 0:x<temp.length:x++){  
            System.out.println(temp\[x\]+"."):  
        }  
        System.out.println():// 换行  
    }  
}

以上的代码虽然可以实现转置,但是会产生垃圾,而我们开发的原则,应该是产生越少的垃圾越好
   
    第二种实现方式:在一个数组上实现转置(计算公式:数组长度\2)

public class arrayAndMethod{
public static void main(String args[]){
int data [] = new int[]{19,8,37,6,55,4,73,2,91,0}:
reverse(data):
printArray(data):
}
public static void reverse(int arr[]){
int center = arr.length/2:
int head = 0:
int tail = arr.length - 1:
for(int x = 0:x<center:x++){
int temp = arr[head]:
arr[head] = arr[tail]:
arr[tail] = temp:
head ++:
tail --:
}
}
public static void printArray(int temp[]){ // 接收一个数组
for(int x = 0:x<temp.length:x++){
System.out.println(temp[x]+"."):
}
System.out.println():// 换行
}
}

以上都是方法接收数组的形式,下面再来看一下方法返回数组的操作,如果某一个方法要返回一个数组,只需要将方法的返回值类型声明为数组即可
        范例:方法返回数组

    public class arrayAndMethod{  
    public static void main(String args\[\]){  
        int data \[\] = init():

        printArray(data):  
    }  
    public static void int \[\]init(){  
        return new int\[\]{19,8,37,6,55,4,73,2,91,0}:  // return null: 也是没有问题的  
    }  
    public static void printArray(int temp\[\]){  // 接收一个数组  
        for(int x = 0:x<temp.length:x++){  
            System.out.println(temp\[x\]+"."):  
        }  
        System.out.println():// 换行  
    }  
}

如果返回的是引用数据类型,那么返回null语法上是没有任何问题的

/*    对象数组
        对象数组的使用,以及内存的分配操作
    
    对象数组的核心概念;某一个数组之中的保存的都是对象,所以对于对象数组的定义格式有以下两种
        动态初始化:类名称 对象数组名称[] = new 类名称[长度]:
        静态初始化:类名称对象数组名称 [] = new 类名称[]{实例化对象,……}
        
    范例:使用动态初始化定义对象数组

    cladss Object{  
        private String name:  
        private int age:

        public Object(String n,int a){  
            name = n:  
            age = a:  
        }  
        // 无参构造  setter getter 省略  
        public String getlnfo(){  
            return"姓名"+neme+",年龄"+age:  
        }  
    }  
    public cladss objectArray{ // 程序必须有类  
        public static void main(Stirng args\[\]){  
            Object per \[\] = new Object\[3\]: // 开辟了一个包含有三个元素的对象数组  
            for(int x = 0:x<per.length:x++){  
                System.out.println(per\[x\].getlnfo):  
            }  
        }  
    }

使用动态初始化操作形式产生的对象数组,里面的每一个元素都是null(累是引用数据类型)
        
        添加数据:

   public cladss objectArray{ // 程序必须有类  
        public static void main(Stirng args\[\]){  
            objectArray per \[\] = new objectArray\[3\]:   

         // 开辟了一个包含有三个元素的对象数组
per[] = new Object("小三",10):
per[] = new Object("小四"12):
per[] = new Object("小五",15):
for(int x = 0:x<per.length:x++){
System.out.println(per[x].getlnfo):
}
}
}

累本身属于引用数据类型,那么所有的对象一定都会保存在对内存空间,而对象数组包含的是一组对象
 
     除了动态初始化之外也可以进行静态初始化的操作
        范例:静态初始化对象数组

public cladss objectArray{ // 程序必须有类
public static void main(Stirng args[]){
objectArray per [] = new objectArray[3]: // 开辟了一个包含有三个元素的对象数组
Object perA = new Object("小三",10):
Object perB = new Object("小四",12):
Object perC = new Object("小五",15):
Object per [] = new Object[]{perA,perB,perC}:
for(int x = 0:x<per.length:x++){
System.out.println(per[x].getlnfo):
}
}
}

第二种

public cladss objectArray{ // 程序必须有类
public static void main(Stirng args[]){
objectArray per [] = new objectArray[3]: // 开辟了一个包含有三个元素的对象数组
Object per [] = new Object[]{
new Object("小三",10),
new Object("小四",12),
new Object("小五",15)}:
for(int x = 0:x<per.length:x++){
System.out.println(per[x].getlnfo):
}
}
}

/*    总结
        有了对象数组的概念之后实际上就是相当于简单JAVA类的概念有进一步进行了提升
        如果是基本数据类型,则数组里面只保存数据,而如果保存了对象 那么每个元素可以保存更多的内容
        但是数组永远都有自己的缺陷    长度是固定的
*/

/*    与数组有关的类库
        java 本身提供有一系列的开发类库帮助用户进行代码编写,那么下面首先给出两个基本的数组操作方法
        1.数组拷贝:一下的语法与原始定义有出入,以后在细化;
            拷贝:System.arraycopy(原始数组,原始数组开始点,目标数组,目标数组的开始点,拷贝长度):
        范例:数组拷贝
            原始数组1:1,2,3,4,5,6,7,8,9
            原始数组2:10,20,30,40,50,60,70,80,90
            希望实现数组2部分内容替换掉数组1的内容:1,60,70,80,5,6,7,8,9

    public class classLobraries{  
        public static void main(String args\[\]){  
            int data1\[\] = new int\[\]{1,2,3,4,5,6,7,8,9}:  
            int data2\[\] = new int\[\]{10,20,30,40,50,60,70,80,90}:  
            System,arraycopy(data2,5,data1,1,3):  
            printArray(data1):  
        }  
    }    

/*    数组排序
        语法:java.util.Arrays.sort(数组名称):
        范例:数组排序

        public class arrayAndMethod{  
            public static void main(String args\[\]){  
                int data\[\] = new int \[\]{89,10,20,1,0,2,8,3,90,67,9,7}:  
                java.util.Arrays.sort(data):  
                printArray(data):

            public static void printArray(int temp\[\]){  // 接收一个数组  
                for(int x = 0:x<temp.length:x++){  
                    System.out.println(temp\[x\]+"."):  
                }  
                System.out.println():// 换行  
            }  
        }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

这种方式是在代码实际开发中使用的,千万要记住别在面试里完成

/*总结
    1,数组属于引用数据类型
    2,数组属于线性的存储结构,里面的内容可以根据索引线性操作
    3,数组里面容易出现面试题

*/