目录
一.数组的基本用法
1.什么是数组
2.创建数组
动态初始化
静态初始化
3.数组的基本使用
获取数组长度
访问数组元素
遍历数组元素
以字符串打印数组
二.数组作为方法的参数
1.基本用法
2.理解引用类型
传内置类型
传引用类型
3. 认识null
4.初识 JVM 内存区域划分
三.数组作为方法的返回值
四.数组的拷贝
1.for循环进行拷贝
2.Arrays.copyOf进行拷贝
3. Arrays.copyOfRange进行拷贝
4.通过System.arraycopy进行拷贝
5.通过array.clone()进行拷贝
6.深拷贝和浅拷贝
五.数组经典习题
1.查找最大元素
2.求数组中元素的平均值
3.查找数组中指定元素
顺序查找
二分查找
4.检查数组的有序性
5.数组排序
冒泡排序
Arrays.sort
6.数组逆序
7.数组数字排列
六.二维数组
1.基本语法
2.代码示例
3.具体用法
总结-思维导图
数组:储存一组相同数据类型的数据的集合
本质:就是让我们能 "批量" 创建相同类型的变量
举例:比如我们创建一个整型变量可以使用int a = 1;那么如果创建多个整型变量就可以使用数组int [] array = {...}
注意事项:需要注意的是,在Java中,数组储存的变量必须是同一类型!!
基本语法:数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };
接下来举个例子来深入理解一下:
public class TestDemo {
public static void main(String[] args) {
int[] array = new int[]{1,2,3,4,5};
}
}
基本语法:数据类型[] 数组名称 = { 初始化数据 };
同样的,我们来举个例子:
public class TestDemo {
public static void main(String[] args) {
int[] array2 = {1,2,3,4,5,6};
}
}
需要注意的是: 静态初始化的时候, 数组元素个数和初始化数据的格式是一致的
public class TestDemo {
public static void main(String[] args) {
int[] array = new int[]{1,2,3,4,5};
System.out.println("length:"+array.length);
}
}
使用 array.length 能够获取到数组的长度," . " 这个操作为成员访问操作符,后面在面向对象中会经常用到
public class TestDemo {
public static void main(String[] args) {
int[] array = new int[]{1,2,3,4,5};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
System.out.println(array[4]);
}
}
1.使用 [ ] 按下标取数组元素,需要注意的是,下标从 0 开始计数,所以下标访问操作不能超出有效范围 [0, length - 1] ,如果超出有效范围,会出现下标越界异常
2. 使用 [ ] 操作既能读取数据, 也能修改数据
法一:使用for循环遍历数组元素
public class Demo {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
for (int i = 0; i <= array.length-1 ; i++) {
System.out.print(array[i]+" ");
}
}
}
法二:使用for each循环遍历数组元素
for each循环:又称增强for循环,是 for 循环的另外一种使用方式,能够更方便的完成对数组的遍历,可以避免循环条件和更新语句写错。但是for each循环是拿不到下标的,用在集合中比较多
public class Demo {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
for (int x : array) {
System.out.print(x+" ");
}
}
}
如果我们要打印一个数组,除了写一个打印方法外还能怎么打印呢?首先我们来试一下直接打印,打印出来是:[I@1b6d3586,这显然不是我们想要的。直接打印行不通,这时候我们就需要借助Java的操作数组的工具类Arrays.toString,将参数的数组以字符串的形式进行输出
import java.util.Arrays;//导入数组工具类包
public class Demo {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
System.out.println(Arrays.toString(array));
}
}
public class Demo {
public static void printArray(int[] a){
for (int x : a) {
System.out.print(x+" ");
}
}
public static void main(String[] args) {
int [] array = {1,2,3,4,5};
printArray(array);
}
}
在这里,你可以看到int [] a是形参,而int [] array是实参
public class Demo2 {
public static void func(int x){
x = 10;
System.out.println("x:"+x);
}
public static void main(String[] args) {
int num = 20;
func(num);
System.out.println("num:"+num);
}
}
我们发现,修改形参x的值,并不影响实参num的值!
//以传输组为例
public class Demo3 {
public static void exchange(int[] array){
int temp = array[0];
array[0] = array[1];
array[1] = temp;
}
public static void main(String[] args) {
int[] array ={1,2,3,4,5};
System.out.println("交换前:");
System.out.println("array[0]="+array[0]+",array[1]="+array[1]);
exchange(array);
System.out.println("交换后:");
System.out.println("array[0]="+array[0]+",array[1]="+array[1]);
}
}
通过这个运行结果我们可以发现,以数组为参数传参就可以修改变量的值,这是为什么呢?
1.原来,此时的array是一个引用变量,里面储存的是变量的地址。
2.引用指向的是对象,前面提到了对象储存在堆上面!Java中是能拿到堆上的地址的!
接下来再通过图来具体分析一下来帮助理解:
关于引用的注意事项:
1.引用一定在栈上吗?这取决与变量的性质,如果是局部变量,就一定在栈上,如果是实例化成员变量就不一定了
2.一个引用能同时指向多个对象吗?不能!一个引用只能有一个对象!
null:在 Java 中表示 "空引用" , 也就是一个无效的引用
接下来通过代码让大家具体感受一下
public class Demo4 {
public static void exchange(int[] array){
int temp = array[0];
array[0] = array[1];
array[1] = temp;
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
exchange(null);
}
}
代码运行时报错了,我们来具体分析一下报错原因以及解决方案
在传引用的时候null会报出空指针异常,null的作用类似于C语言中的null,都表示一个无效的内存位置,因此不能进行任何读取操作
接下来一张图带你详细了解JVM区域划分
这里补充一下Native 方法: JVM 是一个基于 C++ 实现的程序。在 Java 程序执行过程中,本质上也需要调用 C++ 提供的一些函数进行和操作系统底层进行一些交互。因此在 Java 开发中也会调用到一些 C++ 实现的函数。这里的 Native 方法就是指这些 C++ 实现的,再由Java 来调用的函数
我们来写一个方法将数组元素都乘以2
import java.util.Arrays;
public class Demo4 {
public static void transform(int[] array) {
for (int i = 0; i < array.length; i++) {
array[i] = array[i] * 2;
}
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
transform(array);
System.out.println(Arrays.toString(array));
}
}
这样写没有任何问题,但是会破坏原来数组,如果我们不希望破坏原来数组,应该怎样写呢?这时候需要在方法内部创建一个新的数组,并且返回该数组,接下来看看具体的代码实现
import java.util.Arrays;
public class Demo4 {
public static int[] transform(int[] array) {
int[] array2 = new int[array.length];
for (int i = 0; i < array.length; i++) {
array2[i]=2*array[i];
}
return array2;
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] ret = transform(array);//创建一个数组来接收array2
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(ret));
}
}
这样做就可以不破坏原来数组啦!同时,由于数组是引用类型,返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效
import java.util.Arrays;
public class Demo5 {
public static int[] copyArray(int[] array){
int[] copy = new int[array.length];//定义一个数组的大小
for (int i = 0; i < array.length; i++) {
copy[i] = array[i];
}
return copy;
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
System.out.println(Arrays.toString(copyArray(array)));
}
}
我们通过帮助手册来了解一下copyOf的作用和使用方法:copyOf(需要拷贝的数组,拷贝的长度)
接下来通过代码实现
import java.util.Arrays;
public class Demo5 {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] ret = Arrays.copyOf(array,array.length);
System.out.println(Arrays.toString(ret));
}
}
通过Arrays.copyOfRange拷贝局部
public class Demo5 {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] ret = Arrays.copyOfRange(array,0,5);
System.out.println(Arrays.toString(ret));
}
}
相信看到 下标为5还不越界 这里一定有些懵, 这是因为Java的from和to都是左闭右开的,这里的to 5相当于<5,那就是取到4这里!
在使用Arrays.copyOf进行拷贝的时候,我们将光标移动到Arrays.copyOf上,按下ctrl键,可以得到
发现Arrays.copyOf调用了System.arraycopy,我们按住ctrl,点击System.arraycopy分析一下用法
import java.util.Arrays;
public class Demo5 {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] copy = new int[array.length];
System.arraycopy(array,0,copy,0,array.length);
System.out.println(Arrays.toString(copy));
}
}
.clone()会产生一个副本,里面的内容和原来的数组一模一样
import java.util.Arrays;
public class Demo6 {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] copy = array.clone();
System.out.println(Arrays.toString(copy));
}
}
首先来了解一下这俩的概念:
深拷贝:修改拷贝后的数组不会影响到原数组
浅拷贝:修改拷贝后的数组会影响到原数组
总结:想要达到深拷贝,需要对对象本身进行拷贝。刚刚我们所举得例子全是深拷贝。
如果数组放的是基本数据类型,就是深拷贝。如果数组放的是引用类型那就是浅拷贝。
温故而知新,接下来提供一些经典习题供读者练习,同时附上笔者解法,如有错误,请斧正!
给定一个整型数组, 找到其中的最大元素 (找最小元素同理)
public class Test1 {
public static void findMax(int[] array){
int max = array[0];//从0下标开始寻找
for (int i = 0; i < array.length; i++) {
if(array[i]>max){
max = array[i];
}
}
System.out.println(max);
}
public static void main(String[] args) {
int[] array = {1,5,7,9,11};
findMax(array);
}
}
给定一个整型数组, 求平均值
public class Test2 {
public static double average(int[] array){
int sum = 0;
for (int i = 0; i < array.length; i++) {
sum += array[i];
}
double num = (double)sum/(double)array.length;
return num;
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
System.out.println(average(array));
}
}
给定一个数组, 再给定一个元素, 找出该元素在数组中的位置.
public class Test3 {
public static int find(int[] array,int toFind){
for (int i = 0; i < array.length; i++) {
if (array[i] == toFind){
return i;
}
}
return -1;//表示未找到
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
System.out.println(find(array,5));
}
}
二分查找有个缺陷,就是只能查找全是升序或者降序的数组,接下来以升序为例
public class Test4 {
public static int binarySearch(int[] array,int toFind){
int left = 0;
int right = array.length-1;
while(left<=right){
int mid =(right+left)/2;
if(toFind>array[mid]){//在右半区去找,并且缩小范围
left = mid+1;
}else if(toFind
给定一个整型数组, 判断是否该数组是有序的(升序)
public class Test5 {
public static boolean func(int[] array){
for (int i = 0; i < array.length; i++) {
if(array[i]
给定一个数组, 让数组升序 (降序) 排序
import java.util.Arrays;
public class Test6 {
public static void bubbleSort(int[] array){
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length-1-i ; j++) {
if(array[j]>array[j+1]){
int temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}
}
public static void main(String[] args) {
int[] array = {1,8,9,5,4};
bubbleSort(array);
System.out.println(Arrays.toString(array));
}
}
冒泡排序性能较低. Java 中内置了更高效的排序算法:Array.sort
import java.util.Arrays;
public static void main(String[] args) {
int[] array = {1,8,9,5,4};
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
}
给定一个数组, 将里面的元素逆序排列
思路:给定两个下标分别指向第一个元素和最后一个元素,让这两个元素交换,然后再实现自增和自减,重复该操作,直到走到数组的最中间
import java.util.Arrays;
public class Test7 {
public static void reverse(int[] array){
int left = 0;
int right = array.length-1;
while(left < right){
int temp = array[left];
array[left] = array[right];
array[right] = temp;
left++;
right--;
}
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
reverse(array);
System.out.println(Arrays.toString(array));
}
}
给定一个整型数组, 将所有的偶数放在前半部分, 将所有的奇数放在数组后半部分
基本思路:设定两个下标分别指向第一个元素和最后一个元素。 用前一个下标从左往右找到第一个奇数,用后一个下标从右往左找到第一个偶数,然后交换两个位置的元素. 依次循环即可
import java.util.Arrays;
public class Test8 {
public static void transform(int[] array){
int left = 0;
int right = array.length-1;
while(left < right){
while(left
数据类型[ ][ ] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
Java中二维数组可以省略列,不能省略行
int[][]array = {
{1,2,},{3,4},{5,6}};
int[][]array2 = new int[3][2];
int[][]array3 = new int[][]{
{1,2,},{3,4},{5,6}};
public class TestDemo {
public static void main(String[] args) {
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.printf("%d\t", arr[i][j]);
}
System.out.println("");
}
}
}
二维数组的具体用法与一维数组类似,这里不再赘述