Java数组的转换和拷贝

集合、数组互转

集合 --> 数组

1. 循环添加

 List<String> mlist = new ArrayList();
 mlist.add("A");
 mlist.add("L");
 mlist.add("V");
 String[] arr = new String[mlist.size()];
 // List转换成数组
 for (int i = 0; i < mlist.size(); i++) {
     arr[i] = mlist.get(i);
 }

2. toArray

在这里插入图片描述

Conllection, List, Set接口中都具有toArray()toArray(T[] a)方法。

所以实现这些接口的类都可以使用toArray方法转换为数组。
在这里插入图片描述

ArrayList 中的源码

	// ArrayList 中的源码
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }
	/*
	* @param      src      the source array.源数组
	* @param      srcPos   starting position in the source array.源数组要复制的起始位置
	* @param      dest     the destination array.目的数组
	* @param      destPos  starting position in the destination data.目的数组放置的起始位置
	* @param      length   the number of array elements to be copied.复制的长度
	**/
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

使用示例:

    List<String>  sList = new ArrayList<>();
    sList.add("A");
    sList.add("B");
    sList.add("C");
    Object[] objArr = sList.toArray();

    // String[] errArr  = (String[] )sList.toArray(); // 报错
    // Exception in thread "main" java.lang.ClassCastException:
    // [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; at com.company.Main.main(Main.java:136)

    String[] strArr = sList.toArray(new String[sList.size()]); // 常用此方法

String[] errArr = (String[] )sList.toArray(); // 报错原因
因为java中的强制类型转换是针对单个对象才有效果的,而List是多对象的集合,所以强制转换整个List是错误的。

数组 --> 集合

1. 循环添加

    String[] strs = new String[]{"A", "L", "V", "I", "N"};
    List<String> newList = new ArrayList<String>();
    for(String str : strs)
        newList.add(str);
    System.out.println(newList); // [A, L, V, I, N]
    System.out.println(newList.toString()); // [A, L, V, I, N]
    System.out.println(Arrays.toString(newList.toArray())); // [A, L, V, I, N]

2. asList()

Arrays中有方法asList();
在这里插入图片描述

    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a); 
        // 这儿的ArrayList是Arrays类的内部类,其中没有add(),remove()之类的方法;只能查改、不能增删
    }
    private static class ArrayList<E> extends AbstractList<E>
    implements RandomAccess, java.io.Serializable {...}

这儿的ArrayList是Arrays类的内部类,其中没有add(),remove()之类的方法;只能查改、不能增删

使用示例

    String[] strs = new String[]{"A", "L", "V", "I", "N"};
    List<String> list = Arrays.asList(strs);
    // list.add("can't add or del!!!");
    // Exception in thread "main" java.lang.UnsupportedOperationException
    List<String> newList = new ArrayList<String>(list);
    newList.add("can add or del!!!"); // 利用ArrayList构造方法,将其变为可变集合
    for (String bean : newList) {
        System.out.println(bean);
    }

List<String> list = Arrays.asList(strs);
list.add("can't add or del!!!");
Exception in thread “main” java.lang.UnsupportedOperationException

集合 <–> 集合

1. 构造方法

// 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
ArrayList(Collection<? extends E> c)

LinkedList(Collection<? extends E> c)

// 构造一个包含指定集合中的元素的新集合。
HashSet(Collection<? extends E> c)

// 构造与指定集合相同的元素的新的链接散列集。
LinkedHashSet(Collection<? extends E> c)

// 构造一个包含指定集合元素的deque,按照它们由集合的迭代器返回的顺序。
ArrayDeque(Collection<? extends E> c)

// 创建与指定的枚举映射相同的键类型的枚举映射,最初包含相同的映射(如果有)。
EnumMap(EnumMap<K,? extends V> m)

// 构造一个与给定地图相同的映射的新哈希表。
Hashtable(Map<? extends K,? extends V> t)

// 构造一个新的 HashMap与指定的相同的映射 Map 。
HashMap(Map<? extends K,? extends V> m)

做个测试:判断是浅复制 还是 深复制!

package com.company;

import java.util.ArrayList;
import java.util.List;

public class ClassLoaderTest {
    
    public static void main(String[] args)
    {
        ArrayList<Integer> list = new ArrayList();
        for(int i = 0;i<5;i++)
            list.add(i);
        ArrayList<Integer> copy = new ArrayList(list);
        System.out.println(list); // [0, 1, 2, 3, 4]
        System.out.println(copy); // [0, 1, 2, 3, 4]
        System.out.println(list.get(0) == copy.get(0)); // true
        System.out.println(list.get(0).equals(copy.get(0))); // true
        // ---------------------------------------------------
        ArrayList<String> list2 = new ArrayList();
        for(int i = 6;i<10;i++)
            list2.add(String.valueOf(i));
        ArrayList<String> copy2 = new ArrayList(list2);
        System.out.println(list2); // [6, 7, 8, 9]
        System.out.println(copy2); // [6, 7, 8, 9]

        System.out.println(list2.get(0) == copy2.get(0)); // true
        System.out.println(list2.get(0).equals(copy2.get(0))); // true
        
        // --------------------------------------------------------
        ArrayList<TreeNode> list3 = new ArrayList();
        for(int i = 10;i<15;i++)
            list3.add(new TreeNode(i));
        ArrayList<TreeNode> copy3 = new ArrayList(list3);
        System.out.println(list3); // [10, 11, 12, 13, 14]
        System.out.println(copy3); // [10, 11, 12, 13, 14]
        copy3.get(0).val = 1000; 
        System.out.println(list3.get(0) == copy3.get(0)); // true
        System.out.println(list3.get(0).equals(copy3.get(0))); // true
        System.out.println(list3); // [1000, 11, 12, 13, 14]
        System.out.println(copy3); // [1000, 11, 12, 13, 14]
    }
}

class TreeNode {
     int val;
     TreeNode(int val) { this.val = val; }
    public String toString()
    {
        return String.valueOf(val);
    }
}

对于引用类型,构造方式是直接复制地址!!!

Integer、String具有特殊性

Java拷贝(赋值、浅拷贝、深拷贝)

2. addAll() 方法

实现了List接口的类具有该方法:ArrayList、LinkedList

    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

数组的拷贝

  1. for循环
  2. clone()
  3. System.arraycopy()
  4. Arrays.copyOf()

1. for

for循环是一种很灵巧的数组拷贝方式,经常可以自己封装成方法去使用。

记不住其他的方式时候,自己手敲,最方便了。

2. clone()

protected native Object clone() throws CloneNotSupportedException;

这是数组的clone()方法。

      User u1 = new User(1,"1",null);
      User u2 = new User(2,"2",u1);
      User u3 = new User(3,"3",u2);
      User[] users = new User[3];
      users[0] = u1; users[1] = u2; users[2] = u3;
      User[] users_c = users.clone();

      users_c[0].id = 9;
      users_c[0].name = "change";
      users_c[0].friend = users_c[2];
      System.out.println(users_c == users); 		// false
      System.out.println(users_c[0] == users[0]); 	// true
      System.out.println(users[0].toString()); 		// [9-change-3]
      System.out.println(users_c[0].toString()); 	// [9-change-3]

发现对于引用类型的数组 复制的是数组元素的地址

3. System.arraycopy()

	/*
	* @param      src      the source array.源数组
	* @param      srcPos   starting position in the source array.源数组要复制的起始位置
	* @param      dest     the destination array.目的数组
	* @param      destPos  starting position in the destination data.目的数组放置的起始位置
	* @param      length   the number of array elements to be copied.复制的长度
	**/
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

native修饰,底层用c或者c++实现的,但没有返回值,clone()还需要对返回值进行类型转换,它的速度是要比clone()要快。
四种拷贝中最快的肯定是System.arraycopy()。

4. Arrays.copyOf()

Arrays.copyOf(original, newLength);
Arrays.copyOfRange(original, from, to);

两者本质上还是调用的System.arraycopy(...)方法

源码

基本数据类型

	// 基本数据类型都是调用的 System.arraycopy(...)方法
    public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

    public static int[] copyOfRange(int[] original, int from, int to) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        int[] copy = new int[newLength];
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        return copy;
    }

引用数据类型

    public static <T> T[] copyOf(T[] original, int newLength) { 
        return (T[]) copyOf(original, newLength, original.getClass());
    }

    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

    public static <T> T[] copyOfRange(T[] original, int from, int to) {
        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
    }
    
    public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        return copy;
    }

两者本质上还是调用的System.arraycopy(...)方法

使用

// 基本数据类型使用 B 代替
// 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。
static B[] copyOf(B[] original, int newLength)
// 将指定数组的指定范围复制到新数组中。
static B[]	copyOfRange(B[] original, int from, int to)

// 对象
// 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。
static <T> T[]	copyOf(T[] original, int newLength)

// 将指定数组的指定范围复制到新数组中。
static <T> T[]	copyOfRange(T[] original, int from, int to)


tips

基本数据类型都是直接复制值!

那么引用类型呢?见下:

除了String,一般引用数据类型都是直接复制数组元素地址。
浅拷贝是针对单个对象来说的。而这儿讨论的是数组的复制。

String

     String[] strs = new String[]{"A", "L", "V", "I", "N"};
     List<String> newList = new ArrayList<String>();
     String[] strs_c = Arrays.copyOf(strs, strs.length);
     strs_c[0] ="exchange";
     System.out.println(Arrays.toString(strs)); // [A, L, V, I, N]
     System.out.println(Arrays.toString(strs_c)); // [exchange, L, V, I, N]
     System.out.println(strs == strs_c);             // false
     System.out.println(strs[0] == strs_c[0]);       // false
     System.out.println(strs[0].equals(strs_c[0]));  // false

System.arraycopy(...)Arrays.copyOf(...) : 重新创建String对象

自定义数据类型

class User{
    int id;
    String name;
    User friend;
    public User(int id,String name,User friend){
        this.friend =friend;
        this.id = id;
        this.name = name;
    }

    public String toString(){
        return "["+this.id + "-"+ this.name +"-"+ this.friend.id + "]";
    }
}

class Main{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        User u1 = new User(1,"1",null);
        User u2 = new User(2,"2",u1);
        User u3 = new User(3,"3",u2);
        User[] users = new User[3];
        users[0] = u1; users[1] = u2; users[2] = u3;
        User[] users_c = Arrays.copyOf(users,3);

        users_c[0].id = 9;
        users_c[0].name = "change";
        users_c[0].friend = users_c[2];
        System.out.println(users_c == users); 		// false
        System.out.println(users_c[0] == users[0]); // true
        System.out.println(users[0].toString()); 	// [9-change-3]
        System.out.println(users_c[0].toString()); 	// [9-change-3]
    }
}

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        User u1 = new User(1,"1",null);
        User u2 = new User(2,"2",u1);
        User u3 = new User(3,"3",u2);
        User[] users = new User[3];
        users[0] = u1; users[1] = u2; users[2] = u3;
        User[] users_c = users.clone();   //使用数组的clone()方法也一样
        
        users_c[0].id = 9;
        users_c[0].name = "change";
        users_c[0].friend = users_c[2];
        System.out.println(users_c == users); 		// false
        System.out.println(users_c[0] == users[0]); // true
        System.out.println(users[0].toString()); 	// [9-change-3]
        System.out.println(users_c[0].toString()); 	// [9-change-3]
    }

System.arraycopy(...)Arrays.copyOf(...) 还有 数组[].clone() : 都是复制每个对象的地址,等同于 users_c[0] = users[0];


java数组的四种拷贝方式
Java拷贝(赋值、浅拷贝、深拷贝)

基本数据类型

待增加

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值