【Java宝典】——探索数组的奥秘之旅

CSDN 2024-10-08 09:05:04 阅读 98

](https://img-home.csdnimg.cn/images/20220524100510.png#pic_center)

🌈个人主页: Aileen_0v0

🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法

💫个人格言:“没有罗马,那就自己创造罗马~”

文章目录

`Java数组常见报错``①:ArrayIndexOutOfBoundsException(数组索引超出范围)``②:NullPointerException(空指针异常)`

`数组的三种遍历方式``Java中栈和堆的关系``Java中の数据类型``数组作为返回值进行进行返回`

数组练习数组转字符串数组的copy✨️ `数组的复制``方法1:使用copyof进行复制``方法2:使用copyofRange进行部分复制``方法3:使用arraycopy进行复制``方法4:使用clone进行复制`

`数组的扩容``顺序查找数组中的指定元素``法1:循环查找-有序无序都适用``法2:二分查找-使用前提:元素必须按照从小到大排序`

`通过Arrays中的equals关键字判断数组是否相等``Arrays局部填充用fill关键字``冒泡排序``冒泡排序流程图`

<code>Java数组常见报错

①:ArrayIndexOutOfBoundsException(数组索引超出范围)

public static void main(String[] args) { -- -->

//java常见报错1:

boolean[] array2 = new boolean[10];

System.out.println(array2[10]);

}

在这里插入图片描述


<code>②:NullPointerException(空指针异常)

public static void main(String[] args) { -- -->

//java常见报错2:

int[] array = null;

System.out.println("数组的长度是: " +array.length);

}

在这里插入图片描述


<code>数组的三种遍历方式

public static void main(String[] args) { -- -->

int[] array = { 1,2,3,4};

//Java循环遍历方式1:访问下标形式

for (int i = 0 ; i < array.length; i++){

System.out.print(array[i]+" ");

}

System.out.println();

//Java循环遍历方式2:for-each 只是遍历程序,不能通过下标访问

for (int Aileen : array){

System.out.print(Aileen + " ");

}

System.out.println();

//Java遍历循环方式3:toString将数组转换为字符串

String ret= Arrays.toString(array);

System.out.println(ret);

}


public class X {

public static void main(String[] args) {

int[] array1 = new int[3];

array1[0] = 10;

array1[1] = 20;

array1[2] = 30;

System.out.println(array1);

int[] array2 = new int[]{ 1,2,3,4,5};

array2[0] = 100;

array2[1] = 200;

System.out.println(array2);

array1 = array2;

array1[2] = 300;

array1[3] = 400;

array2[4] = 500;

System.out.println(array1);

System.out.println(array2);

}

}

在这里插入图片描述

array1这个引用 指向 array2这个引用所指向的对象

在这里插入图片描述

在这里插入图片描述

array1 和 array2这两个引用 指向 的都是array2这个引用所指向的对象
0x87这个对象 当没有引用 再指向这个对象,就被JVM回收了.
int[] array = null;

代表array这个引用 不指向任何对象.

这就意味着0不能调用它的下标,长度等


<code>Java中栈和堆的关系

栈(Stack)是一种后进先出(LIFO)的数据结构,用于存储方法调用和局部变量。

每当一个方法被调用时,Java虚拟机会为该方法创建一个栈帧,并将其推入栈中。

栈帧包含了方法的参数、局部变量以及方法返回时需要的信息。

当方法执行完毕后,对应的栈帧会被弹出,释放相应的内存空间。

堆(Heap)是用于动态分配对象的内存区域。

在Java中,所有通过new关键字创建的对象都存储在堆中。

堆是一种可扩展的内存区域,它的大小可以根据需要进行调整。

堆中的对象可以被多个线程共享,因此需要进行线程安全的管理。

栈和堆之间的关系是:栈中存储了对堆中对象的引用。

当我们在栈中声明一个对象引用变量时,实际上只是在栈中创建了一个引用,而对象本身仍然存储在堆中。

通过引用变量,我们可以访问和操作堆中的对象。

____

<code>Java中の数据类型

在Java中,数据类型可以分为基本数据类型和引用数据类型。

基本数据类型是Java语言中预定义的数据类型,它们包括整数类型(byte、short、int、long)、浮点数类型(float、double)、字符类型(char)和布尔类型(boolean)。

基本数据类型的值直接存储在变量中,它们占用固定的内存空间,并且在内存中分配的位置是连续的。

基本数据类型的赋值是将值直接复制给变量。

引用数据类型是由程序员定义的类、接口、数组等类型。

引用数据类型的变量存储的是对象的引用(内存地址),而不是对象本身。

引用数据类型的变量在内存中占用的空间大小是固定的,但它们指向的对象可以动态地分配和释放内存。

引用数据类型的赋值是将对象的引用复制给变量,多个变量可以指向同一个对象。

基本数据类型和引用数据类型的区别总结如下:

<code>存储方式:基本数据类型的值直接存储在变量中,而引用数据类型的变量存储的是对象的引用。内存分配:基本数据类型在内存中分配的位置是连续的,而引用数据类型的对象可以动态地分配和释放内存。大小固定性:基本数据类型占用固定的内存空间,而引用数据类型的变量在内存中占用的空间大小是固定的。赋值方式:基本数据类型的赋值是将值直接复制给变量,而引用数据类型的赋值是将对象的引用复制给变量。


public class X { -- -->

public static void main(String[] args) {

int[] array = { 1,2,3,4};

fun1(array);

//打印第一个函数的值

System.out.println(Arrays.toString(array));

System.out.println(array);

}

public static void fun1(int[] array22){

array22 = new int[]{ 11,22,33,44,55};

}

}

在这里插入图片描述

因为引用只是修改了形参(局部变量)的指向,当程序执行完以后,形参和其对应的堆上的地址就会自动销毁.

程序最后的打印结果是1,2,3,4所以说不是传了引用,就一定能够修改实参的值

在这里插入图片描述

在这里插入图片描述

①形参不能改变实参的值的情况(只修改指向)

因为引用只是修改了形参(局部变量-红色框框内)的指向[这两个引用分别指的是不同的对象.],当程序执行完以后,形参和其对应的堆上的地址(对象)就会自动销毁.

程序最后的打印结果是1,2,3,4所以说不是传了引用,就一定能够修改实参的值

引用变量当中存地址

引用指向对象

在这里插入图片描述

②形参可以改变实参的值的情况(修改同一个指向所指向的对象)

<code>public class X { -- -->

public static void main(String[] args) {

int[] array = { 1,2,3,4};

fun2(array);

for (int i = 0 ; i < array.length; i++){

System.out.print(array[i]+" ");

}

System.out.println();

System.out.println(array);

}

public static void fun2(int[] array11){

array11[0] = 99;

}

}

两个引用(array和array11)同时指向同一个对象,所以通过形参修改,实参也会跟着改变
从上面的例子也可以看出,形参和实参的名字可以一样也可以不一样.

<code>public class X { -- -->

public static void main(String[] args) {

int x = 10;

func4(x);

System.out.println(x);

}

public static void func4(int a){

a = 20;

}

}

在这里插入图片描述

从上面的例子可以看出, 传入基本数据类型,不能通过形参修改实参的数值.

<code>数组作为返回值进行进行返回

public class X { -- -->

public static void main(String[] args) {

int[] ret = func5();

System.out.println(

Arrays.toString(ret)

);

}

public static int[] func5(){

int[] array = { 1,2,3,4};

return array;

}

}

在这里插入图片描述

在这里插入图片描述

首先创建的ret数组先访问函数func5,

其次为创建的array(引用)这个数组开辟一块空间然后指向堆上的地址0x99.

然后将array的值返回出来赋值给ret,并且指向array的对象,

最后打印并返回出array的值.


数组练习

数组转字符串

<code>public class X { -- -->

public static void main(String[] args) {

int[] arr = { 1,2,3,4,5,6};

//创建方法的对象

String ret = myToString(arr);

System.out.println(ret);

}

//自己创造的转为字符串的方法

public static String myToString(int[] arr) {

String ret = "[";

for (int i = 0; i < arr.length; i++) {

ret += arr[i];

if(i != arr.length-1 ){

ret += ",";}

}

ret += "]";

return ret;

}

}

public class X {

//但是下面这种写法漏了判断array是否为null的情况.

public static void main(String[] args) {

int[] array = null;

String ret = myToString(array);

System.out.println(array);

}

public static String myToString(int[] array){

//判断数组array为null的情况

if (array == null){

return "null";

}

String ret = "[";

for (int i=0;i < array.length;i++){

ret += array[i];

if (i != array.length- 1){

ret += ",";

}

}

ret += "]";

return ret;

}

}


数组的copy

public class X {

//但是下面这种写法漏了判断array是否为null的情况.

public static void main(String[] args) {

//先定义一个数组

int[] array = { 1,2,4,5,8};

//开始复制:首先复制他原来的数组空间大小

int[] copy = new int [array.length];

//通过循环遍历,将原数组的值传入到新创建的数组

for (int i = 0; i < copy.length; i++) {

copy[i] = array[i];

}

//打印新创建数组的值

System.out.print(Arrays.toString(copy));

}

}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


✨️ <code>数组的复制

方法1:使用copyof进行复制

import java.util.Arrays;

public class x { -- -->

public static void main(String[] args) {

int[] array ={ 1,2,3,4};

//拷贝 array 这个数组 ,长度为 array.length

int[] copy = Arrays.copyOf(array,array.length);

System.out.println(Arrays.toString(copy));

}

}

在这里插入图片描述

<code>方法2:使用copyofRange进行部分复制

在JAVA中数组的复制from…to范围一般是左闭右开的,如下所示:

import java.util.Arrays;

public class x { -- -->

public static void main(String[] args) {

int[] array = { 1,2,3,4,5};

int[] copy = Arrays.copyOfRange(array,1,3);

System.out.println(Arrays.toString(copy));

}

}

在这里插入图片描述

<code>方法3:使用arraycopy进行复制

所有被native修饰的是由C/C++进行实现的,所有我们不能看到这个方法的源码,但是它的优点是运行速度比较快

import java.util.Arrays;

public class x { -- -->

public static void main(String[] args) {

int[] array = { 1,2,3,4,5};

int[] dest = new int[array.length];

System.arraycopy(array,0,dest,0,array.length);

System.out.println(Arrays.toString(dest));

}

}

arraycopy方法括号里面参数的含义用通俗的话讲就是从array这个书架的0位置开始拿书把它放到dest这个书架的0位置,这些书的长度是array.length。

方法4:使用clone进行复制

import java.util.Arrays;

public class x {

public static void main(String[] args) {

int[] array = { 1,2,3,4,5};

int[] copy = array.clone();

System.out.println(Arrays.toString(copy));

}

}


数组的扩容

将数组扩大2倍

public class X {

public static void main(String[] args) {

//数组扩容

int[] array = { 1,2,3,4};

//拷贝array 这个数组 ,新的长度为 array.length * 2

array = Arrays.copyOf(array,array.length*2);

//array 指向了 新的数组空间

System.out.println(Arrays.toString(array));

}

}

在这里插入图片描述


<code>顺序查找数组中的指定元素

法1:循环查找-有序无序都适用

public class FindElement { -- -->

// 主方法,程序的入口点

public static void main(String[] args) {

// 定义并初始化一个整型数组 array

int[] array = { 1,2,5,4,5};

// 定义并初始化另一个整型数组 myarray

int[] myarray = { 9,8,7,6,5};

// 调用 search 方法搜索数组 array 中的元素 556,并打印返回值

System.out.println(search(array, 556));

// 调用 search2 方法搜索数组 myarray 中的元素 8,并打印返回值

System.out.println(search2(myarray, 8));

}

// 定义一个静态方法 search,用于在整型数组中搜索给定的 key 值

public static int search(int[] array, int key) {

// 遍历数组

for (int i = 0; i < array.length; i++) {

// 如果找到 key 值,返回当前索引

if (array[i] == key) {

return i;

}

}

// 如果没有找到 key 值,返回 -1

return -1;

}

// 定义另一个静态方法 search2,与 search 方法功能相同,用于在整型数组中搜索给定的 key 值

public static int search2(int[] array, int key) {

// 遍历数组

for (int i = 0; i < array.length; i++) {

// 如果找到 key 值,返回当前索引

if (array[i] == key) {

return i;

}

}

// 如果没有找到 key 值,返回 -1

return -1;

}

}

法2:二分查找-使用前提:元素必须按照从小到大排序

import java.util.Arrays; // 导入 Arrays 类,用于数组操作

public class BinarySearch {

public static void main(String[] args) {

int[] array = { 5, 3, 6, 8, 7}; // 定义并初始化一个整型数组

Arrays.sort(array); // 使用 Arrays 类的 sort 方法对数组进行排序

System.out.println(Arrays.toString(array)); // 打印排序后的数组,输出格式为 [3, 5, 6, 7, 8]

// 调用 binarySearch 方法在数组中搜索键值 111,并打印返回结果

System.out.println(binarySearch(array, 111));

}

// 定义一个静态方法 binarySearch,用于在排序后的数组中进行二分查找

public static int binarySearch(int[] array, int key) {

int i = 0; // 初始化左边界索引为 0

int j = array.length - 1; // 初始化右边界索引为数组长度减 1

while (i <= j) { // 当左边界索引小于等于右边界索引时,继续循环

int mid = (i + j) / 2; // 计算中间索引

if (array[mid] < key) { // 如果中间索引处的值小于键值,说明键值在右半部分

i = mid + 1; // 将左边界索引移动到中间索引的下一个位置

} else if (array[mid] == key) { // 如果中间索引处的值等于键值,返回中间索引

return mid; // 找到键值,返回其索引

} else { // 如果中间索引处的值大于键值,说明键值在左半部分

j = mid - 1; // 将右边界索引移动到中间索引的前一个位置

}

}

// 如果没有找到键值,返回 -1

return -1;

}

}

除了通过自己写二分查找以外,Java还可以直接调用Arrays库里面的binarySearch直接进行二分查找。

import java.util.Arrays; // 导入 Arrays 类,用于数组操作

public class BinarySearch {

public static void main(String[] args) {

int[] array = { 5, 3, 6, 8, 7}; // 定义并初始化一个整型数组

Arrays.sort(array); // 使用 Arrays 类的 sort 方法对数组进行排序

System.out.println(Arrays.toString(array)); // 打印排序后的数组,输出格式为 [3, 5, 6, 7, 8]

// 调用 binarySearch 方法在数组中搜索键值 111,并打印返回结果

System.out.println(Arrays.binarySearch(array, 7));

}

}


我们除了通过使用Arrays类里面的sort进行从小到大排序以外,还可以利用reverse进行逆向排序。

import java.util.Arrays; // 导入Arrays类,用于调用数组相关的工具方法,如toString()

public class ReverseSorted {

public static void main(String[] args) {

int[] array = { 1,2,3,31,14,5}; // 定义并初始化一个整型数组

reverse(array); // 调用reverse方法,传入数组作为参数

System.out.println(Arrays.toString(array)); // 打印数组的字符串表示,查看反转后的结果

}

public static void reverse(int[] array){ // 定义一个名为reverse的方法,用于反转数组

int i = 0; // 初始化索引i为0,指向数组的起始位置

int j = array.length-1; // 初始化索引j为数组长度减1,指向数组的末尾位置

while (i < j){ // 当索引i小于索引j时,继续循环

int temp = array[i]; // 将索引i处的元素暂存到临时变量temp

array[i] = array[j]; // 将索引j处的元素赋值给索引i处

array[j] = temp; // 将临时变量temp的值(原索引i处的元素)赋值给索引j处

i++; // 索引i向后移动一位

j--; // 索引j向前移动一位

}

}

}


通过Arrays中的equals关键字判断数组是否相等

import java.util.Arrays;

public class Equals {

public static void main(String[] args) {

int [] array1 = { 1,8,4,5};

int [] array2 = { 1,8,4,5};

int [] array3 = { 1,2,3,3};

System.out.println(Arrays.equals(array1,array2));

System.out.println(Arrays.equals(array1,array3));

}

}


Arrays局部填充用fill关键字

import java.util.Arrays;

public class PartFill

{

public static void main(String[] args) {

int [] array = new int[10];

Arrays.fill(array,1,3,99);//下标1-2处填充为99

System.out.println(Arrays.toString(array));

}

}

在这里插入图片描述


<code>冒泡排序

冒泡排序流程图

在这里插入图片描述

<code>import java.util.Arrays;

public class BubbleSort { -- -->

public static void main(String[] args) {

int[] array = { 1,5,3,2,9};

System.out.println(Arrays.toString(array));

bubbleSort(array);

System.out.println(Arrays.toString(array));

}

public static void bubbleSort(int[] array){

//循环要比较的趟数 , 5个数据比较4趟

for(int i = 0 ; i < array.length-1;i++ ){

//---优化:假设本来就有序,进入下面的循环则变为无序。

boolean order = false;//假设有序

//循环控制每趟比较次数 , 因为每一次比上一次少比较一趟

for (int j = 0; j < array.length - 1 - i;j++){

if (array[j] > array[j+1]) {

int temp = array[j];

array [j] = array[j+1];

array[j+1] = temp;

order = true;

}

}

//如果为false则有序,直接返回

if (order == false) {

return;

}

}

}

}




声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。