arrays.copyof方法到底是深度复制还是浅度复制; 我们做一个实验: 编写测试类:
package Copy;
import java.util.Arrays;
/**
* @Author: sunsuhai
* @Date: 2018/11/18 17:42
*/
public class Copy {
public static void doSomeing(){
int[] a = new int[5];
int[] b = new int[5];
System.out.println("a数组的地址:"+a);
System.out.println("b数组的地址:"+b);
int[] c = Arrays.copyOf(a,5);
System.out.println("c数组的地址:"+c);
}
public static void doSomeing2(){
SunShuai[] a = new SunShuai[5];
SunShuai[] b = Arrays.copyOf(a,5);
System.out.println("a数组的地址:"+a);
System.out.println("b数组的地址:"+b);
SunShuai sunShuai = new SunShuai(1,"123");
a[0] = sunShuai;
SunShuai[] c = Arrays.copyOf(a,5);
System.out.println("a数组的地址:"+a);
System.out.println("c数组的地址:"+c);
System.out.println("a[0]元素的地址:"+a[0]);
System.out.println("c[0]元素的地址:"+c[0]);
System.out.println("a[0]元素的地址:"+a[0]);
System.out.println("c[0]元素的地址:"+c[0]);
a[0].setInfo("456");
a[0].setCode(2);
System.out.println("a[0]元素的内容:"+a[0]);
System.out.println("c[0]元素的内容:"+c[0]);
}
public static void main(String[] args) {
//doSomeing();
doSomeing2();
}
}
class SunShuai{
private int code;
private String info;
public SunShuai(int code, String info) {
this.code = code;
this.info = info;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
// @Override
// public String toString() {
// return "SunShuai{" +
// "code=" + code +
// ", info='" + info + '\'' +
// '}';
// }
}
输出结果为:
a数组的地址:[LCopy.SunShuai;@5a07e868
b数组的地址:[LCopy.SunShuai;@76ed5528
a数组的地址:[LCopy.SunShuai;@5a07e868
c数组的地址:[LCopy.SunShuai;@2c7b84de
a[0]元素的地址:Copy.SunShuai@3fee733d
c[0]元素的地址:Copy.SunShuai@3fee733d
a[0]元素的地址:Copy.SunShuai@3fee733d
c[0]元素的地址:Copy.SunShuai@3fee733d
a[0]元素的内容:Copy.SunShuai@3fee733d
c[0]元素的内容:Copy.SunShuai@3fee733d
我们可以看到,数组的值并不改变; 点进arrays.copyof的源码我们可以看到
@SuppressWarnings("unchecked")
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
关于@suppressWarning的解释可以看上一篇笔记 @suppressWarning 他调用了内部的copyof方法,多传递了一个对象类型
我们再看copyof方法
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;
}
创建一个新的数组,然后调用system.arraycopy方法;
graph LR
a --> SunShuai-0
a --> SunShuai-1
a --> b
b --> Sunshuai-0-0
b --> Sunshuai-0-1
Sunshuai-0-0 --> SunShuai-0
Sunshuai-0-1 --> SunShuai-1
System.arraycopy分析
static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst,
jint dstPos, jint length) {
const jint count = length;
ScopedFastNativeObjectAccess soa(env);
// 目标数组和源数组的空值检验
if (UNLIKELY(javaSrc == nullptr)) {
ThrowNullPointerException("src == null");
return;
}
if (UNLIKELY(javaDst == nullptr)) {
ThrowNullPointerException("dst == null");
return;
}
// 确保两个对象都是数组
ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
if (UNLIKELY(!srcObject->IsArrayInstance())) {
ThrowArrayStoreException_NotAnArray("source", srcObject);
return;
}
ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
if (UNLIKELY(!dstObject->IsArrayInstance())) {
ThrowArrayStoreException_NotAnArray("destination", dstObject);
return;
}
ObjPtr<mirror::Array> srcArray = srcObject->AsArray();
ObjPtr<mirror::Array> dstArray = dstObject->AsArray();
// 数组越界检查
if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) ||
UNLIKELY(srcPos > srcArray->GetLength() - count) ||
UNLIKELY(dstPos > dstArray->GetLength() - count)) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
"src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos,
count);
return;
}
ObjPtr<mirror::Class> dstComponentType = dstArray->GetClass()->GetComponentType();
ObjPtr<mirror::Class> srcComponentType = srcArray->GetClass()->GetComponentType();
Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType();
if (LIKELY(srcComponentType == dstComponentType)) {
// Trivial assignability.
switch (dstComponentPrimitiveType) {
//我们可以看到,如果是基本类型,会调用memmove方法
case Primitive::kPrimVoid:
LOG(FATAL) << "Unreachable, cannot have arrays of type void";
UNREACHABLE();
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U);
dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count);
return;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U);
dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count);
return;
case Primitive::kPrimInt:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count);
return;
case Primitive::kPrimFloat:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
dstArray->AsFloatArray()->Memmove(dstPos, srcArray->AsFloatArray(), srcPos, count);
return;
case Primitive::kPrimLong:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count);
return;
case Primitive::kPrimDouble:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
dstArray->AsDoubleArray()->Memmove(dstPos, srcArray->AsDoubleArray(), srcPos, count);
return;
case Primitive::kPrimNot: {
//如果是对象类型,那么调用AssignableMemmove方法
mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count);
return;
}
default:
LOG(FATAL) << "Unknown array type: " << srcArray->PrettyTypeOf();
UNREACHABLE();
}
}
// If one of the arrays holds a primitive type the other array must hold the exact same type.
if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) ||
srcComponentType->IsPrimitive())) {
std::string srcType(srcArray->PrettyTypeOf());
std::string dstType(dstArray->PrettyTypeOf());
soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
"Incompatible types: src=%s, dst=%s",
srcType.c_str(), dstType.c_str());
return;
}
// Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove.
ObjPtr<mirror::ObjectArray<mirror::Object>> dstObjArray =
dstArray->AsObjectArray<mirror::Object>();
ObjPtr<mirror::ObjectArray<mirror::Object>> srcObjArray =
srcArray->AsObjectArray<mirror::Object>();
// If we're assigning into say Object[] then we don't need per element checks.
if (dstComponentType->IsAssignableFrom(srcComponentType)) {
dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count);
return;
}
// This code is never run under a transaction.
DCHECK(!Runtime::Current()->IsActiveTransaction());
dstObjArray->AssignableCheckingMemcpy<false>(dstPos, srcObjArray, srcPos, count, true);
}