数组的延伸(浅复制、深复制)

本文介绍Java中数组的深复制与浅复制概念,并通过具体示例展示复制过程。同时,提供了数组合并、一维转二维数组及其求和、最大最小值计算等实用案例。

数组的复制:
       浅复制:数组的名称(引用数据类型)指向的是相同的堆空间。
       深复制:重新开辟新的内存空间去存储数组的数据。


package lesson_arr;

import java.util.Arrays;
public class Demo {
public static void main(String[] args) {

//浅复制
int[] arr1 = {12,34,56,78};
int[] arr2 = arr1;
System.out.println("没修改数值之前的arr1:");
print(arr1);
//print(arr2);
System.out.println("修改数值之后的arr1:");
arr2[1] = 100;
print(arr1);

//深复制一
int[] arr3 = arr1.clone();
System.out.println("arr3:");
print(arr3);
arr3[1] = 50;
print(arr1);
System.out.println(arr1+"==="+arr3);

//深复制二
int len = arr1.length;
int[] arr4 = new int[len];
for (int i = 0; i < arr1.length; i++) {
arr4[i] = arr1[i];
}

//深复制三
int[] arr5 = Arrays.copyOf(arr1, arr1.length);
print(arr5);
arr5[1] = 98;
print(arr1);

//深复制四(重点)
/*src-源数组
srcPos-源数组起始位置
dest-目标数组
destPos-目标数组起始位置
length-要复制的数组元素的数量*/
int[] arr6 = {6,7,8,9,10,5};
int[] arr7 = new int[5];
System.arraycopy(arr1, 0, arr6, 0, arr1.length);//覆盖arr6前面的数据
print(arr6);
/*System.arraycopy(arr1, 0, arr7, 0, arr1.length);
print(arr7);*/
}
//遍历数组
public static void print(int[] arr) {
for (int num : arr) {
System.out.print(num+" ");
}
System.out.println();
}

}

案例一:实现两个数组的合并。
package lesson_arr;
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) {
int[] str1 = { 1, 7, 9, 11, 13, 15, 17, 19 };
int[] str2 = { 2, 4, 6, 8, 10 };
int strLen1 = str1.length;// 保存第一个数组长度
int strLen2 = str2.length;// 保存第二个数组长度
str1 = Arrays.copyOf(str1, strLen1 + strLen2);// 扩容,也可以实现复制
System.arraycopy(str2, 0, str1, strLen1, strLen2);// 将第二个数组与第一个数组合并
System.out.println("合并数组为:"+Arrays.toString(str1));// 输出数组
getNum(str1);//排序
}
}
案例二:将一维数组转化为二维数组,并求和、最小值及最大值。
package lesson_arr;
import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
int[][] arr1 = new int[3][4];//定义一个二维数组
int[] arr2 = { 4, 4, 34, 37, 3, 12, 2, 6, 5, 17, 9, 11 };//定义一个一维数组
     //将arr2转化为arr1
int n = 0;
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1[i].length; j++) {
arr1[i][j] = arr2[n];
n++;
}
}
print(arr1);//打印转化后的二维数组
getAdd(arr1);
getMax(arr1);
getMin(arr1);
}
    //二维数组求和方法
public static void getAdd(int[][] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
System.out.println("和为:" + sum);
}
    //二维数组求最大值
public static void getMax(int[][] arr) {
int maxNum = arr[0][0];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (maxNum < arr[i][j]) {
maxNum = arr[i][j];
}
}
}
System.out.println("最大值为:"+maxNum);
}
   //二维数组求最小值
public static void getMin(int[][] arr) {
int maxNum = arr[0][0];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (maxNum > arr[i][j]) {
maxNum = arr[i][j];
}
}
}
System.out.println("最小值为:"+maxNum);
}
   // 二维数组遍历方法
public static void print(int[][] arr) {
for (int i = 0; i < arr.length; i++) {// 行数
//System.out.println();
for (int j = 0; j < arr[i].length; j++) {// 列数
//System.out.print("arr[" + i + "][" + j + "]=" + arr[i][j]+"\t");
}
}
System.out.println(Arrays.deepToString(arr));
}
}

<think> 嗯,用户询问的是关于console.log输出数组时需要展开才能完整复制的原因和解决方案。让我梳理一下站内引用中的关键信息: 从引用[1]中找到了核心解释:console.log对引用类型是惰性求值的。当输出数组时,它只记录引用地址而不是快照,等到用户点击展开时才读取当前值。如果期间数组被修改(比如在循环中异步修改),展开时看到的就是修改后的值。 引用[5]补充了异步场景的案例:当数组在异步回调中被修改时,初始console.log显示空数组长度,但展开后能看到被修改后的内容。这解释了为什么展开前后的数据表现不一致。 关于解决方案,综合所有引用可以提炼出三种可靠方法: 1. 序列化方案:用JSON.stringify()深拷贝当前状态(引用[1]的思路延伸) 2. 浏览器原生方案:console.table()直接结构化展示(引用[3]提到的衍生方法) 3. 快照方案:通过展开运算符[...arr]创建浅拷贝(引用[5]的解决思路) 特别注意到引用[3]提到不同浏览器对console方法的实现差异,所以方案设计时需要兼顾兼容性。异步场景的解决方案要额外强调深拷贝的必要性,避免用户掉进引用类型陷阱。 用户应该是前端开发者,遇到的实际问题可能是调试时无法及时获取数组快照。需要提醒展开复制不完整可能导致调试偏差,比如异步操作前后的数据对比错误。在表格方案说明中加入具体截图建议会更实用。 </think> 在使用 `console.log()` 输出数组时需要手动展开才能完整复制数据,根本原因在于 JavaScript 控制台对引用类型的**惰性求值机制**,具体分析和解决方案如下: --- ### **原因分析** 1. **引用类型惰性求值** `console.log()` 输出数组、对象等引用类型时,控制台**仅记录引用地址而非数据快照**。当你在控制台点击展开数组时,浏览器才会实时读取该地址的**当前值**(即使此时原始数组已被修改)[^1][^5]。 2. **异步操作导致数据延迟** 若数组在异步回调中被修改(如 `fetch`、`setTimeout`),初始 `console.log()` 输出的是执行时的**空数组或旧数据**。展开时呈现的却是异步完成后的**最终值**,导致数据"不一致"[^5]。 3. **控制台优化机制** 浏览器为避免性能损耗,默认折叠大型数据结构(如长数组),需手动展开才能查看/复制完整内容[^3][^4]。 --- ### **解决方案** #### 方法一:强制立即快照(推荐) ```javascript // 深拷贝当前状态(适合简单数据) console.log(JSON.parse(JSON.stringify(myArray))); // 浅拷贝当前状态(适合基础类型数组) console.log([...myArray]); ``` **原理**:通过拷贝创建数据快照,避免惰性求值影响[^1][^5]。 #### 方法二:结构化输出 ```javascript // 表格形式展示数组(浏览器支持良好) console.table(myArray); // 分项输出索引与值 myArray.forEach((item, index) => { console.log(`[${index}]:`, item); }); ``` **效果**:直接展开内容,无需手动操作[^3]。 #### 方法三:使用断点调试 1. 在代码中插入 `debugger` 语句 2. 浏览器开发者工具中检查数组的**实时状态** ```javascript debugger; // 暂停执行,查看当前数组值 console.log(myArray); ``` --- ### **异步场景特殊处理** ```javascript // 模拟异步数据更新 let data = []; fetch('api/data').then(res => { data = res.json(); console.log("异步完成:", [...data]); // 拷贝快照 }); console.log("初始状态:", [...data]); // 输出空数组快照 ``` > **关键点**:在异步回调**内部**拷贝数据,确保捕获更新后的值[^5]。 --- ### 总结 | **场景** | **推荐方案** | **优点** | |------------------------|----------------------------------|------------------------------| | 同步输出数组 | `console.log([...array])` | 简单快速,保留数据结构 | | 异步更新后的数组 | 在回调内部使用深拷贝/浅拷贝 | 精准捕获最终值 | | 大型数组查看 | `console.table()` | 无需展开,直观易读 | | 调试复杂数据流 | `debugger` + 断点检查 | 实时观察数据变化过程 | > **避坑提示**:直接复制控制台折叠状态的数组可能丢失数据!务必展开或使用快照输出[^1][^5]。 --- ### 相关问题 1. 如何在异步请求中准确捕获 `console.log` 的输出时机? 2. `console.table()` 对嵌套对象数组的支持程度如何?有何局限性? 3. 除了数组,还有哪些数据类型会受到控制台惰性求值的影响? 4. 如何通过 `console.log` 输出带样式的结构化数据? [^1]: 控制台对引用类型采用惰性求值,展开时读取当前值。 [^3]: `console.table()` 提供结构化表格视图。 [^5]: 异步操作导致数据延迟更新,需在回调内捕获快照。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值