java.lang.System下的arraycopy和java.util.Arrays.copyOf方法
2013-06-27 15:33
645 查看
(1) java.lang.System.arraycopy
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);问题:方法没有任何的实现,具体是如何实现的呢?
以下是关于该方法具体的说明:
* @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.
* @exception IndexOutOfBoundsException if copying would cause
* access of data outside array bounds.
* @exception ArrayStoreException if an element in the <code>src</code>
* array could not be stored into the <code>dest</code> array
* because of a type mismatch.
* @exception NullPointerException if either <code>src</code> or
* <code>dest</code> is <code>null</code>.
(2) java.util.Arrays.copyOf
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) { 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; }
两者的最大区别是:
arraycopy 方法会因为新数组大小比旧数组大小小而报IndexOutOfBoundsExceptioncopyOf 则不会因此报错,因为copyOf 的返回值是在内部new好的copy 数组,而该copy数组new的大小就等于newLength,故即使在客户端指定好了新数组newArray 的大小,接收到返回值后也是指向底层new出来的数组copy换句话说,在客户端代码中即使不给新数组new对象,如:String[]
newStr = null; 那么对于arraycopy 是会报NullPointerException 的错误的,而对于java.util.Arrays 中的copyOf 方法则由于jdk 底层已经new 出了对象而不会报该错误!
不过需要特别注意的是:copyOf 方法最后也是调用System.arraycopy的方法,不过由于前面的准备,异常情况就不会出现了。
下面是一个具体实例:
public class ArrayCopyOf { public static void main(String[] args) { String[] oldStr = new String[6]; setValues(oldStr); String[] newStr = null; newStr = java.util.Arrays.copyOf(oldStr, 6); //System.arraycopy(oldStr, 0, newStr, 0, oldStr.length); // 会报错NullPointerException ,如果改为newStr = new String[5], // 那么调用Arrays.copyOf 方法不会报错,而调用System.arraycopy 方法 // 则回报IndexOutOfBoundsException print(oldStr); print(newStr); System.out.println(oldStr.length); System.out.println(newStr.length); } private static void print(String[] newStr) { // TODO Auto-generated method stub for (int i = 0; i < newStr.length; i++) { System.out.print(newStr[i] + " : "); } System.out.println(); } private static void setValues(String[] oldStr) { // TODO Auto-gemmnerated method stub for (int i = 0; i < oldStr.length; i++) { oldStr[i] = "str " + i; } } }
与此同时,java.util.Arrays 还重载了很多copyOf 方法:
public static byte[] copyOf(byte[] original, int newLength) { byte[] copy = new byte[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } 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; }
等等;
现在再来讨论下ArrayList 中对该两个方法的使用情况:
由于ArrayList 底层是用数组实现的,那么就必然会面临两个问题:(1) 一开始必须要指定一个初始化的数组大小;
java.util.ArrayList 中初始化ArrayList 大小是10 :
private transient Object[] elementData;// 为什么要设置成transient? 不想被序列化? public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); this.elementData = new Object[initialCapacity]; } public ArrayList() { this(10); }
(2) 当数组容量不够时,能够动态增加容量。
java.util.ArrayList 中的add(E e) 方法 public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } }
可见,每次添加元素时,JDK 都会先检查数组elementData 的容量是否已经满了,如果满了,就会调用Arrays.copyOf 方法,用elementData 中的元素和新数组的长度构造一个新的数组,并重新赋值给elementData数组。此处不难看出,由于需求是把长度已经增长了的elementData 数组重新赋值给elementData ,故直接使用System.arraycopy 方法是不适合的。
另外,新数组长度的改变也是有讲究的,JDK 的设计是每次有新的扩展数组长度的需要到来时,就按int newCapacity = (oldCapacity * 3)/2 + 1; 的算法构造新数组的长度,不难看出,这种算法构造出来的新的数组长度的增量都会比上一次大( 而且是越来越大) ,即认为客户需要增加的数据很多,而避免频繁newInstance 的情况。
下面再来看ArrayList 中的toArray 方法
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; }
此处主要看第二个toArray 方法,可见,客户是想把ArrayList 中的元素转换成数组并存放到指定的a 数组中,因此就要判断a.length 与elementData 当前的大小了,如果a.length<size, 那么调用System.arraycopy 方法是肯定会报错的,故必须调用Arrays.copyOf 方法,而如果a.length>=size 那么就比不上调用System.arraycopy 方法来得方便了( 因为根据上面说的,Arrays.copyOf 方法最终也是调用System.arraycopy方法的) 。
综上所述,可以总结:在允许的情况下,尽量调用System.arraycopy 方法,实在不行再调用Arrays.copyOf 方法。
相关文章推荐
- java.lang.System.arraycopy() 与java.util.Arrays.copyOf()的区别
- java数组的拷贝四种方法:for、clone、System.arraycopy、arrays.copyof
- Java之System.arraycopy方法的使用
- Java编程:Arrays.copyOf()与System.arraycopy()的分析
- 关于java.lang.SecurityException: class "org.bouncycastle.util.Strings"'s signer.....报错信息的解决方法
- java.lang.System 的in是final的,为什么要有public static void setIn(InputStream in)方法?
- Arrays.copyof()和System.arraycopy()方法总结
- java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList
- Java方法之--System.arraycopy方法和Arrays.copyOf()
- java.lang.Comparable, java.util.Compartor区别以及Hadoop中关于自定义类型中的compare方法
- Java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader解决方法
- [java]Arrays.copyOf() VS System.arrayCopy()
- java.lang.UnsatisfiedLinkError: Couldn't load xxx from loader dalvik.system.PathClassLoader的解决方法
- java.lang.System.arraycopy()方法使用说明
- java.util.Arrays 静态方法
- tomcat内存溢出的解决方法(java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError:)
- java中System.copyArray与Arrays.copyof区别
- java.lang包中的String类,java.util.regex包中的Pattern,Matcher类中都有matches()方法。
- java:数组操作工具类 java.util.Arrays包 主要方法详解
- 关于mybatis报invalid comparison: java.util.Arrays$ArrayList and java.lang.String异常