详解Java数组的四种拷贝方式

目录
  • 深拷贝与浅拷贝的区别
  • 1.for循环进行拷贝
    • 拷贝数值类型
    • 拷贝引用类型
  • 2.copyof/copyOfRange
    • 拷贝数值类型
    • 拷贝引用类型
  • 3.arraycopy
    • 拷贝数值类型
    • 拷贝引用类型
  • 4.clone
    • 拷贝数值类型
    • 拷贝引用类型
  • 5.总结

深拷贝与浅拷贝的区别

假设现在有原数组A以及拷贝后的数组B,若是改变A中的某一个值,B数组随之相应的发生变化的拷贝方式称为浅拷贝,反之B数组不受影响,则称为深拷贝;
简单总结一下两者的概念:

深拷贝:拷贝后,修改原数组,不会影响到新数组;

浅拷贝:拷贝后,修改原数组,新数组也会相应的发生改变;

1. for循环进行拷贝

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

//1. for循环拷贝  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = new int[A.length];
        for (int i = 0; i < A.length; i++) {
            B[i] = A[i];
        }
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
    }
    //打印对象数组的方法
    public static void show(Num[] arrays) {
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i].getVal() + " ");
        }
        System.out.println();
    }
class Num{
    public int val = 0;

    public Num(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
}

拷贝引用类型

当数组中存放的元素为引用数据类型时,此时发生的是浅拷贝;

//1. for循环拷贝  (拷贝引用数据类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = new Num[4];
        for (int i = 0; i < A.length; i++) {
            B[i] = A[i];
        }
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }

2. copyof / copyOfRange

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

Arrays.copy(原数组,自定义新数组长度);

Arrays.copyOfRange(原数组,from,to);

注意拷贝截取的范围是左闭右开的[from,to)

//2. copy / copyOfRange  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = Arrays.copyOf(A,A.length);
        int[] C = Arrays.copyOfRange(A,1,3);
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("C : " + Arrays.toString(C));  //C : [2, 3]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("C : " + Arrays.toString(C));  //C : [2, 3]
    }

拷贝引用类型

当数组中存放的元素为类的对象时,此时发生的是浅拷贝;

//2. copy / copyOfRange  (拷贝引用类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = Arrays.copyOf(A,A.length);
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }
class Num{
    public int val = 0;

    public Num(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
}

3. arraycopy

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

System.arraycopy(src, srcPos dest, destPos, length);

其中各个参数分别表示 如下:

  • src :源数组
  • srcPos:源数组要复制的起始位置
  • dest:目标数组
  • destPos:目标数组复制的起始位置
  • length:复制的长度

所以srcPos和destPos都为0,且length为源数组长度时,表示完完整整的拷贝过来了;那么截取范围拷贝也举个例子,下面的代码中srcPos = 1,destPos = 2,length = 2,表示从A数组下标为1的位置开始截取2个元素,放到B数组中下标为2的位置作为起始位置,再对比一下输出看看。

//3. arraycopy  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = new int[A.length];
        //System.arraycopy(A,0,B,0,A.length);
        System.arraycopy(A,1,B,2,2);
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [0, 0, 2, 3, 0]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [0, 0, 2, 3, 0]
    }

拷贝引用类型

当数组中存放的元素为类的对象时,此时发生的是浅拷贝;

//3. arraycopy  (拷贝引用类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = new Num[4];
        System.arraycopy(A,0,B,0,A.length);
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }
class Num{
    public int val = 0;

    public Num(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
}

4. clone

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

//4. clone  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = A.clone();
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
    }

拷贝引用类型

当数组中存放的元素为类的对象时,此时发生的是浅拷贝;

//4. clone  (拷贝引用类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = A.clone();
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }

5. 总结

拷贝方式 数值类型 引用类型 推荐使用
for循环 深拷贝 浅拷贝  
copyof 深拷贝 浅拷贝
arraycopy 深拷贝 浅拷贝
clone 深拷贝 浅拷贝  

由于arraycopy底层是C++写的,所以速度快,更多的是使用这个方法。

注意:本文中所有的引用数据类型都是以类的对象为例,使用的是对象数组,我们也知道引用类型包括类,接口,字符串等等。但是需要注意字符串是新的变量,所以如果是连个字符串数组进行拷贝,即使他们是引用类型,但是每次都会创建了一个字符串数组对象, 因此, 修改原数组, 不会影响到新数组,即深拷贝。

以上就是详解Java数组的四种拷贝方式的详细内容,更多关于Java数组拷贝的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java复制(拷贝)数组的4种方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRan

    所谓复制数组,是指将一个数组中的元素在另一个数组中进行复制.本文主要介绍关于 Java 里面的数组复制(拷贝)的几种方式和用法. 在 Java 中实现数组复制分别有以下 4 种方法: Arrays 类的 copyOf() 方法 Arrays 类的 copyOfRange() 方法 System 类的 arraycopy() 方法 Object 类的 clone() 方法 下面来详细介绍这 4 种方法的使用. 使用 copyOf() 方法和 copyOfRange() 方法 Arrays 类的 c

  • java Clone接口和深拷贝详解

    对于数组的拷贝,如果是简单类型的话是深拷贝,如果是引用类型的话是浅拷贝,但是因为java是面向对象的,在回答面试官问题的时候,我们可以不用说的这么细,可以直接说浅拷贝. 代码示例1 class Person implements Cloneable{//如果想克隆自定义类,那么需要在自定义类上实现Cloneable接口 public int age; /*疑问:为什么这个接口是空接口呢?这是一个面试问题. 空节课:也把它叫做标记接口.其实就是这个意思:只要一个类实现了这个接口,那么就标记这个类是

  • Java中的数组复制(clone与arraycopy)代码详解

    JAVA数组的复制是引用传递,而并不是其他语言的值传递. 1.clone protectedObjectclone() throwsCloneNotSupportedException创建并返回此对象的一个副本."副本"的准确含义可能依赖于对象的类.这样做的目的是,对于任何对象x,表达式: x.clone()!=x为true,表达式: x.clone().getClass()==x.getClass()也为true,但这些并非必须要满足的要求.一般情况下: x.clone().equa

  • java编程中拷贝数组的方式及相关问题分析

    JAVA数组的复制是引用传递,而并不是其他语言的值传递. 这里介绍java数组复制的4种方式极其问题: 第一种方式利用for循环: int[] a={1,2,4,6}; int length=a.length; int[] b=new int[length]; for (int i = 0; i < length; i++) { b[i]=a[i]; } 第二种方式直接赋值: int[] array1={1,2,4,6}; int[] array2=a; 这里把array1数组的值复制给arra

  • Java 数组复制clone方法实现详解

    这篇文章主要介绍了Java 数组复制clone方法实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.源码 public class Test1 { public static void main(String[] args) { // Student[] arrs = new Student[] { new Student() { id = "22" } }; C# 可以简写法,Java不支持 Student[] arrs

  • 详解Java数组的四种拷贝方式

    目录 深拷贝与浅拷贝的区别 1.for循环进行拷贝 拷贝数值类型 拷贝引用类型 2.copyof/copyOfRange 拷贝数值类型 拷贝引用类型 3.arraycopy 拷贝数值类型 拷贝引用类型 4.clone 拷贝数值类型 拷贝引用类型 5.总结 深拷贝与浅拷贝的区别 假设现在有原数组A以及拷贝后的数组B,若是改变A中的某一个值,B数组随之相应的发生变化的拷贝方式称为浅拷贝,反之B数组不受影响,则称为深拷贝:简单总结一下两者的概念: 深拷贝:拷贝后,修改原数组,不会影响到新数组: 浅拷贝

  • 详解java中的四种代码块

    在java中用{}括起来的称为代码块,代码块可分为以下四种: 一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. 3.静态代码块: 用static{}包裹起来的代码片段,只会执行一次.静态代码块优先于构造块执行. 4.同步代码块: 使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性.同步代码块需要写在方法中. 二.静态代码块和构造

  • 详解Java文件下载的几种实现方式

    Java文件下载的几种方式,具体如下: public HttpServletResponse download(String path, HttpServletResponse response) { try { // path是指欲下载的文件的路径. File file = new File(path); // 取得文件名. String filename = file.getName(); // 取得文件的后缀名. String ext = filename.substring(filena

  • java数组的三种扩容方式以及程序实现详解

    因为数组是在内存中连续的一段存储空间,所以数组一旦被创建,空间就固定了,长度是不能扩增的. 数组的长度是固定的,如果需要扩充**,必须创建新数组,原数组的长度要复制到新数组中 .** java中,数组类型的变量传值的时候,事实上传递的是数组的地址 . Java数组扩容的原理 1)Java数组对象的大小是固定不变的,数组对象是不可扩容的. 2)利用数组复制方法可以变通的实现数组扩容. 3)System.arraycopy()可以复制数组. 4)Arrays.copyOf()可以简便的创建数组副本.

  • Java详解实现多线程的四种方式总结

    目录 前言 一.四种方式实现多线程 1.继承Thread类创建线程 2.实现Runnable接口创建线程 3.实现Callable接口 4.实现有返回结果的线程 二.多线程相关知识 1.Runnable 和 Callable 的区别 2.如何启动一个新线程.调用 start 和 run 方法的区别 3.线程相关的基本方法 4.wait()和 sleep()的区别 5.多线程原理 前言 Java多线程实现方式主要有四种: ① 继承Thread类.实现Runnable接口 ② 实现Callable接

  • 详解JavaScript如何实现四种常用排序

    目录 一.插入排序 直接插入排序 二.交换排序 (1)冒泡排序 (2)快速排序 三.选择排序 (1)简单选择排序 (2)堆排序 四.归并排序 一.插入排序 插入排序有直接插入排序,折半插入排序,希尔排序,这里只实现常用的直接插入排序 直接插入排序 将左侧序列看成一个有序序列,每次将一个数字插入该有序序列. 插入时,从有序序列最右侧开始比较,若比较的数较大,后移一位. function insertSort(array) { //第一个默认已经排好 for (let i = 1; i < arra

  • 详解Java中的三种流程控制语句

    目录 顺序语句 选择语句 if else的嵌套 switch case default 循环语句 for for in while do while break continue 顺序语句 顺序顾名思义就是程序自上而下执行 public class User { public static void main(String[] args) { String name = "hacker"; int age = 18; String happy = "学习Java";

  • 详解Java中的八种单例创建方式

    目录 定义 使用场景 单例模式八种方式 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线程不安全) 懒汉式(同步方法) 懒汉式(同步代码块) 双重检查锁方式 静态内部类方式 枚举方式 总结 定义 单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法) 使用场景 对于一些需要频繁创建销毁的对象 重量级的对象 经常使用到的对象 工具类对象 数据源 session 单例模式八种方式 饿汉式(静态常量) 代码 /**

  • 一文详解Java线程的6种状态与生命周期

    目录 1.线程状态(生命周期) 2.操作线程状态 2.1.新创建状态(NEW) 2.2.可运行状态(RUNNABLE) 2.3.被阻塞状态(BLOCKED) 2.4.等待唤醒状态(WAITING) 2.5.计时等待状态(TIMED_WAITING) 2.6.终止(TERMINATED) 3.查看线程的6种状态 1.线程状态(生命周期) 一个线程在给定的时间点只能处于一种状态. 线程可以有如下6 种状态: New (新创建):未启动的线程: Runnable (可运行):可运行的线程,需要等待操作

  • 详解Java Callable接口实现多线程的方式

    在Java 1.5以前,创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口.无论我们以怎样的形式实现多线程,都需要调用Thread类中的start方法去向操作系统请求io,cup等资源.因为线程run方法没有返回值,如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. Callable和Future介

随机推荐