文章目录
集合、数组互转
集合 --> 数组
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具有特殊性
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;
}
数组的拷贝
- for循环
- clone()
- System.arraycopy()
- 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拷贝(赋值、浅拷贝、深拷贝)
基本数据类型
待增加