1 数组
数组,一组相关变量的集合,通过下标进行访问数组中的内容,并且数组是引用数据类型在使用数组的时候必须为其开辟内存空间
定义:一组能够存储相同数据类型值得变量的集合。
注:所有数组都有一个属性是length(数组一定有长度);数组位置称为下标。
1.1 数组的基本概念
数组的初始化分为两种分别为 动态初始化以及静态初始化
1.1.1 数组的动态初始化:
格式一:
格式1:数组的定义格式如下(动态的操作格式)
数据类型 数组名称[]=new 数据类型[长度];
数据类型 []数组名称=new 数据类型[长度];
格式2:分步完成
声明数组: 数据类型 数组名称[]=null ;
开辟空间: 数组名称=new 数据类型[长度];
当数组的空间开辟之后,可以通过数组的名称[索引]来操作数组中的内容,数组的索引范围0~数组的长度-1, 数组的索引是从0开始的
由于数组通过一个名称进行统一管理的,数组的内容在输出的时候往往可以利用for循环来进行输出,for循环在使用的时候需要明确的知道循环的次数,数组输出的循环的次数就是数组的长度,数组的长度的取得方式:数组名称.length 的方式取得的
范例:定义并且使用一个数组
public class TestDemo02
{
public static void main(String[]args){
//定义一个数组
int data[]=new int[4]; //定义了一个int类型数组 长度为3
//通过下标操作数组
data[0]=10; //为数组的第一个下标的元素赋值为10
data[1]=20; // 为数组的第二个下标的元素赋值为20;
data[2]=30;
data[3]=40;
for(int i=0;i<data.length;i++){
System.out.print(data[i]+",");
}
}
}
以上的程序,定义了一个int类型的数组,并且默认长度设置为4,随后分别为数组中4个元素赋值,根据这个程序可以画出如下的内存分析图
通过以上的分析,发现数组的内存分配过程,与对象的几乎没有任何区别,只不过对象中保存的是属性,而数组中保存的是各个索引元素的数值
1.1.2 数组的静态初始化
以上为数组的动态初始化,数组在动态初始化并且开辟空间之后,所有的数据类型都是其默认值,那么也可以使用静态初始化的方式,在数组创建的时候为其指定内容
格式: 简写格式
数据类型 数组名称[]={值...值....}
格式:完成格式
数据类型 []数组名称 =new 数据类型[]{值...值....}
范例:数组的静态初始化
public static void main(String[]args){
int data[]={10,20,30,40};
// 0 1 2 3
for(int i=0;i<data.length;i++){
System.out.println(data[i]+",");
}
}
注意:进行数组操作的时候,不要越界,如果数组操作一旦越界则会出现以下异常
总结:对于在开发中到底是使用静态初始化还是使用动态初始化的方式来定义数组呢?
看情况,比如需要操作的内容已经明确的知道了,那么使用静态初始化比较合适,需要操作的数据需要单独的进行配置,单独的赋值那么使用动态初始化比较合适
1.1.3 数组的引用传递
既然数组也是引用数据类型,那么数组能否进行引用传递呢?
范例:数组的引用传递
public class TestDemo02
{
public static void main(String[]args){
//定义一个数组
int data[]=new int[4]; //定义了一个int类型数组 长度为3
//通过下标操作数组
data[0]=10; //为数组的第一个下标的元素赋值为10
data[1]=20; // 为数组的第二个下标的元素赋值为20;
data[2]=30;
int temp[]=data;
temp[0]=100;
for(int i=0;i<data.length;i++){
System.out.print(data[i]+",");
}
}
}
以上程序的运行结果 100.20,30 ,0
该程序使用了数组的引用传递,操作修改了数组的内容,当程序执行到temp[]=data 的时候
相当于temp与data同时指向了一块堆内存空间,而通过temp修改数组,同时data也会发生改变
以上的方式,都是通过声明并且初始化的方式完成,接下来使用分步的方式完成
范例: 分步完成数组的定义及操作
public class TestDemo02
{
public static void main(String[]args){
int data[]=null ; //声明一个数组
data=new int[3]; //开辟3个空间的数组并实例化
data[0]=10;
data[1]=20;
data[2]=30;
for(int i=0;i<data.length;i++){
System.out.print(data[i]+",");
}
}
}
以上的程序使用了先声明,后开辟空间的方式完成,给出如下的内存分析图
注意:数组是引用数据类型,只要是引用数据类型则必须开辟内存空间,否则会出现空指向异常
2 数组与方法
数组的内容,可以进行引用传递,那么把数组做为方法的参数来进行操作,如果一个方法想要接收参数,对应的参数类型必须是数组
范例:使用方法接收数组
public class TestDemo02
{
public static void main(String[]args){
int data[]={10,20,30,40};
print(data); //调用打印数组的方法,并传入实际的数组内容
}
//定义一个方法打印数组中的内容
public static void print(int temp[]){
for(int i=0;i<temp.length;i++){
System.out.print(temp[i]+",");
}
}
}
以上的程序,首先使用了一个静态初始化的方式定义了一个数组,之后将数组传递给了方法print() 该方法的主要目的就是为了打印数组中的内容
通过内存分析图可以发现,使用方法接收数组,和数组的引用传递没有区别
范例:判断一个数字是否实在数组之内(主方法中完成)
public static void main(String[]args){
int data[]={10,20,30,40};
//定义想要查找的内容
int serchData=100;
//flag=true 查找了内容
//flag=false 没有找到内容
boolean flag=false;
for(int i=0;i<data.length;i++){
if(serchData==data[i]){ //说明找到了内容
flag=true;
break; //找到了之后就不在找了 使用break 结束循环
}
}
if(flag){
System.out.println("已经找到了内容");
}else{
System.out.println("没有找到内容");
}
}
以上代码虽然可以完成功能,但是在主方法中发现代码太多了,在面向对象中的标准就是及逆行模块化的开发, 在主程序中继续进行拼装,也可以理解为主方法的代码越少越好
范例:使用方法实现
//定义一个查找数组的方法
public static boolean isExists(int[]temp, int searchData){ //如何设计方法的参数
for(int i=0;i<temp.length;i++){
if(searchData==temp[i]){
return true;
}
}
return false;
}
public static void main(String[]args){
int data[]={10,20,30,40};
if(isExists(data,60)){
System.out.println("已经找到了内容");
}else{
System.out.println("没有找到内容");
}
}
以上的方法用于接收一个数组,并且在数组中进行内容的查找并且返回找到的标记直接使用return返回
范例: 在方法里修改数组的内容
public static void main(String[]args){
int data[]={10,20,30,40};
inc(data); //调用数组扩大的方法
print(data); //调用数组打印的方法
}
//定义一个扩大数组的方法,并且参数中传入一个数组
public static void inc(int temp[]){
for(int i=0;i<temp.length;i++){
temp[i]*=2; //扩大数据
}
}
以上的代码在经过方法中把数组的内容改变了,之后方法结束之后,继续输出源数组中的data发现改变后的数据依然有效
接下来通过内存分析图,来理解以下方法中数组内容改变的过程
数组的操作
数组的遍历
获取数组中的元素,通常会用到遍历。(for 循环)
数组中有一个属性可以直接获取到数组元素个数:length
使用方式:数组名称.length =
public class Test1{
public static void printArray(int[] array){
System.out.print("{");
for (int i = 0; i < array.length; i++){
if (i == array.length - 1){
System.out.print(array[i]);
}else{
System.out.print(array[i] + ",");
}
}
System.out.print("}");
}
public static void main(String[] args){
int[] array = {1,2,3,4};
printArray(array);
}
}
注意:System.out.println(arr);出现以下情况
输出的为 数组类型的引用,储存的是int类型的数据。@后的是数组的内存存放地址(16进制)。(由哈希算法算出的哈希值)
获取数组的最大值
思路:
1,获取最值需要比较,每一次比较都会有一个较大的值,因为该值不确定。通过一个临时变量进行储存。
2,让数组中的每一个元素都和这个变量进行比较如果大于了变量的值,就用该变量记录较大值。
3,当所有的元素都完成比较,那么该变量中存储的就是数组中的最大值了
public class Test{
// 获取数组的最大值
public static int getMax(int[] array){
int max = 0;
for (int i = 0; i < array.length; i++){
if(array[i] > array[max]){
max = i;
}
}
return array[max];
}
// 方法的重载
public static double getMax(double[] array){
int max = 0;
for (int i = 0; i < array.length; i++){
if(array[i] > array[max]){
max = i;
}
}
return array[max];
}
// 获取数组的最小值
public static int getMin(int[] array){
int min = 0;
for (int i = 0; i < array.length; i++){
if (array[i] < array[min]){
min = i;
}
}
return array[min];
}
public static void main(String[]args){
int[] array = {1,7,7,89,3,6};
int max = getMax(array);
System.out.println("max="+max);
int min = getMin(array);
System.out.println("min="+min);
}
}
数组排序
选择排序
图示思路分析:
为什么排序方法返回值类型是void,操作的是同一数组。
程序示例:
public class Test{
// 数组遍历功能
public static void printArray(int[] array){
System.out.print("{");
for (int i = 0; i < array.length; i++){
if (i == array.length -1){
System.out.print(array[i]);
}else{
System.out.print(array[i]+",");
}
}
System.out.println("}");
}
// 选择排序(从小到大)
public static void paiXu(int[] array){
for (int i = 0; i < array.length - 1; i++){
for (int j = i + 1; j < array.length; j++){
if (array[i] > array[j]){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
// 选择排序(从大到小)
public static void paiXu1(int[] array){
for (int i = 0; i < array.length - 1; i++){
for (int j = i + 1; j < array.length; j++){
if (array[i] < array[j]){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
public static void main(String[]args){
int[] array = {2,3,1,7,6,9,23,12};
printArray(array);
paiXu1(array);
printArray(array);
}
}
选择排序特点:内循环结束一次,最值出现在头角标位置上。
冒泡排序
图示思路分析:
程序示例:
import java.util.*;
public class Test{
// 数组遍历功能
public static void printArray(int[] array){
System.out.print("{");
for (int i = 0; i < array.length; i++){
if (i == array.length -1){
System.out.print(array[i]);
}else{
System.out.print(array[i]+",");
}
}
System.out.println("}");
}
// 选择排序(从小到大)
public static void paiXu(int[] array){
for (int i = 0; i < array.length - 1; i++){
for (int j = i + 1; j < array.length; j++){
if (array[i] > array[j]){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
// 选择排序(从大到小)
public static void paiXu1(int[] array){
for (int i = 0; i < array.length - 1; i++){
for (int j = i + 1; j < array.length; j++){
if (array[i] < array[j]){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
// 冒泡排序
public static void maoPao(int[] array){
// for (int i = array.length - 1; i > 0; i--){}
// for (int j = 0; j < i; j++){}
for (int i = 0; i < array.length; i++){
for(int j = 0; j < array.length - i - 1; j++){ // -x:让每一次比较的元素减少;-1:避免角标越界
if(array[j] > array[j+1]){
int temp = array[j];
array[j] = array[j+1];
temp = array[j+1];
}
}
}
}
public static void main(String[]args){
int[] array = {2,3,1,7,6,9,23,12};
printArray(array);
//paiXu1(array);
maoPao(array);
printArray(array);
Arrays.sort(array);// java数组排序工具,实际开发工具
printArray(array);
}
}
以上完成的所有的方法都是使用一个方法接收数组的操作,那么可不可以使用一个方法来返回一个数组,只需要把返回值类型定义为数组类型
范例: 通过方法返回数组
//定义一个初始化数组的方法
public static int[] init(){
int temp[]={1,3,5,6,2,8,10,5};
return temp;
}
练习:要求定义一个方法 在这个方法中求出一个数组中的最大值 最小值 总和 以及平均值
(在一个方法中返回4个内容)
public static void main(String[]args){
//在main方法中 传入一个数组进行计算
//定义一个数组用于接收计算的结果
int[]data={1,4,6,2,9,3,8};
int[]result=stat(data); //调用方法
System.out.println("最大值="+result[0]);
System.out.println("最小值="+result[1]);
System.out.println("总和="+result[2]);
System.out.println("平均值="+result[3]);
}
//定义一个方法 求数组的最大值 最小值 总和 平均值 并且返回
public static int[] stat(int temp[]){
//定义一个数组 保存返回的结果
int result[]=new int[4]; //使用动态初始化完成
//假设数组中第一个元素为最大值
// 1 4 6 2 9 3 8
result[0]=temp[0]; //现在result[0]就表示为max
//假设数组中的第一个元素为最小值
result[1]=temp[0]; //现在result[1] 表示最小值
//编写for循环修改最大值与最小值
for(int i=0;i<temp.length;i++){
if(result[0]<temp[i]){ //需要更改最大值
result[0]=temp[i];
}
if(result[1]>temp[i]){ //更改最小值
result[1]=temp[i];
}
result[2]+=temp[i]; //累加总和
}
result[3]=result[2]/temp.length; //平均值
return result;
}
通过以上的代码,当一个方法需要返回多个内容的时候,可以使用数组来完成
与数组相关的操作方法
为了开发方便,java也为用户提供一些与数组相关的操作方法,用户可以直接调用即可
数组的排序 基本语法:java.util.Arrays.sort();
数组拷贝: 从一个数组中把内容拷贝到另外一个数组中 方法名称为System.arraycopy
通过观察源码如下
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
Src: 需要拷贝的数组
srcPos:源数组中的起始位置
Dest:目标数组
destPos:目标数据的起始位置
Length:要拷贝数组的长度
例如现在给定两个数组进行操作:
数组A :1 2 3 4 5 6
数组B: 7 8 9 10 11 12 13
把数组B的部分内容替换到数组A中
范例: 数组的拷贝
int[]A={1,2,3,4,5,6};
int[]B={7,8,9,10,11,12,13};
System.arraycopy(B,0,A,0,2);
print(A);
对象数组
之前讲解的数组,都是基本数据类型的数组,如果要在数组中表示多个对象,则必须要使用到对象数组的概念,对象数组的定义格式和之前的数组的定义格式完全一样,只要把数据类型修改为类名称即可
格式: 对象数组的动态初始化
类名称 对象数组名称[]=new 类名称[长度]
注意:使用了对象数组动态初始化之后,默认值都是为null
格式: 对象数组的静态初始化
类名称 对象数组的名称=new 类名称[]{实例化对象,实例化对象......}
范例:对象数组的动态初始化
Person per[]=new Person[3]; //定义了对象数组 长度为3
per[0]=new Person("张三",20);
per[1]=new Person("李四",30);
per[2]=new Person("隔壁老王",40);
for(int i=0;i<per.length;i++){
System.out.println(per[i].getInfo());
}
范例: 对象数组的静态初始化
public static void main(String[]args){
Person per[]=new Person[]{new Person("张三",20),new Person("李四",30)};
for(int i=0;i<per.length;i++){
System.out.println(per[i].getInfo());
}
}
二维数组(了解)
之前定义的数组只有一个[],表示一维数组,如果定义数组的时候存在两个[]表示为二维数组
首先观察一维数组
二维数组:
从上图的分析中,可以发现二维数组就是类似于一个表格,从目前的领域二维数组使用的频率不大
二维数组的定义格式如下:
格式:动态初始化
数据类型 数组名称[][]=new 数据类型[行数][列数]
格式:静态初始化
数据类型 数组名称[][]=new 数据类型[][]{值...值...}
范例:定义二维数组,静态初始化的方式
public static void main(String[]args){
int data[][]=new int[][]{{1,2,3},{4,5,6},{7,8,9}}; //定义一个二维数组
for(int i=0;i<data.length;i++){ //行循环
for(int y=0;y<data[i].length;y++){
System.out.print(data[i][y]+",");
}
System.out.println();
}
}
综合程序
import java.util.*;
public class Test{
// 数组遍历输出
public static void printArray(int[] array){
System.out.print("{");
for (int i = 0; i < array.length; i++){
if (i == array.length - 1){
System.out.print(array[i]);
}else{
System.out.print(array[i] + ",");
}
}
System.out.print("}" + "\n");
}
// 求最大值
public static void getMax(int[] array){
int max = 0;
for (int i = 0; i < array.length; i++){
if (array[max] < array[i]){
max = i;
}
}
System.out.println("max = " + max);
}
// 求最小值
public static void getMin(int[] array){
int min = 0;
for (int i = 0; i < array.length; i++){
if (array[min] > array[i]){
min = i;
}
}
System.out.println("min = " + min);
}
// 选择排序
public static void selectSort(int[] array){
for (int i = 0; i < array.length - 1; i++){
for (int j = i + 1; j < array.length; j++){
if (array[i] > array[j]){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
// 冒泡排序
public static void bubbleSort(int[] array){
for (int i = 0; i < array.length - 1; i++){
for (int j = 0; j < array.length - i - 1; j++){
if (array[j] > array[j + 1]){
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
// 二分法
public static int dichotomy(int[] array, int x){
if (array == null){
return -1;
}
if (array.length == 0){
return 0;
}
int low = 0;
int high = array.length - 1;
while(low <= high){
// middle = (low + high) / 2 = (low + low + high - low) / 2 = low - (low - high) / 2
int middle = low - (low - high) / 2;
if (x > array[middle]){
low = middle +1;
}else if (x < array[middle]){
high = middle - 1;
}else if (x == array[middle]){
return middle;
}else{
return -1;
}
}
return -1;
}
// 在一个方法中返回数组最大值、最小值、和、平均值:返回类型为数组型
public static int[] getMax_Min_Sum_Average(int[] array){
int[] result = new int[4];
result[0] = array[0];
result[1] = array[0];
for (int i = 0; i < array.length; i++){
if (result[0] < array[i]){
result[0] = array[i];
}
if (result[1] > array[i]){
result[1] = array[i];
}
result[2] += array[i];
}
result[3] = result[2] / array.length;
return result;
}
// 二维数组遍历
public static void erWei(int[][] array){
for (int i = 0; i < array.length; i++){
for (int j = 0; j < array[i].length; j++){
System.out.print(array[i][j] + ",");
}
System.out.println();
}
}
//
public static void main(String[]args){
int[] array = {3,76,1,56,7,23,5};
printArray(array);
selectSort(array);
printArray(array);
int[] array1 = {2,4,54,23,13,8,65};
bubbleSort(array1);
printArray(array1);
int x = dichotomy(array,76);
if (x == -1 || x == 0){
System.out.println("数组无此元素");
}else{
System.out.println("数组有此元素");
}
int[] array2 = getMax_Min_Sum_Average(array);
printArray(array2);
// 对象数组....动态初始化
// 静态初始化...HeHe[] array3 = new HeHe[]{new HeHe("zz", 16), new HeHe("zz", 16), new HeHe("zz", 16)};
HeHe[] array3 = new HeHe[3];
array3[0] = new HeHe("zz", 16);
array3[1] = new HeHe("zz", 16);
array3[2] = new HeHe("zz", 16);
for (int i = 0; i < array3.length; i++){
array3[i].tell();
}
// 二维数组
int[][] array4 = new int[][]{{1,2,3}, {2,3,4}, {3,4,5}};
erWei(array4);
int[] array5 = {4,65,34,13,67,4,7};
Arrays.sort(array5);// 调用Java工具类
printArray(array5);
int[]A={1,2,3,4,5,6};
int[]B={7,8,9,10,11,12,13};
System.arraycopy(B,0,A,0,2);// Java copy 工具,Src: 需要拷贝的数组; srcPos:源数组中的起始位置; Dest:目标数组 ;destPos:目标数据的起始位置 ;Length:要拷贝数组的长度
printArray(A);
}
}
class HeHe{
private String name;
private int age;
public HeHe(){}
public HeHe(String n, int a){
name = n;
age = a;
}
public void tell(){
System.out.println("姓名:" + name + ",年龄:" + age);
}
}