首先来个开胃小菜,复习一下前面的内容
数组的复制:
package com.java.coutClass;
public class Baby {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Baby(String name) {
this.name=name;
}
}
客户端:package com.java.coutClass;
import java.util.Arrays;
public class CopyOfTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Baby[] baby=new Baby[2];
baby[0]=new Baby("Rainday1");
baby[1]=new Baby("Rainday2");
Baby[] A=Arrays.copyOf(baby, 2);//复制数组
Baby[] C=new Baby[2];
System.arraycopy(A, 0, C, 0, 2);// 复制数组A到C
// A[0].setName("Copy Rainday1");
baby[0].setName("orginal Rainday1"); //使 name 指向新的对象
// C[0].setName("C Copy Rainday1");
display(baby);
display(A);
display(C);
System.out.println(A[0].equals(C[0]));
System.out.println(A[0]==C[0]);
/**运行结果:
* orginal Rainday1
Rainday2
orginal Rainday1
Rainday2
orginal Rainday1
Rainday2
true
true
*/
//说明复制的两个数组对象里面的第一元素对象是同一个,所以会出现对其中任何一个的首个元素对象的属性值进行修改都会改变的状况。
// 意味着 baby[0],A[0],C[0] 都指向同一个Baby对象。 浅克隆。。。。。http://blog.youkuaiyun.com/u011625768/article/details/42461985
// 浅克隆 :只复制对象的引用,不复制引用的对象。
}
public static void display(Baby[] baby){
for (Baby baby2 : baby) {
System.out.println(baby2.name);
}
}
}
在java中,数组是一种效率最高的存储和随机访问对象引用序列的方式。
在项目设计中数组使用的越来越少了,而且它确实是没有List、Set这些集合使用方便,但是在某些方面数组还是存在一些优势的,例如:速度,而且集合类的底层也都是通过数组来实现的。
数组的速度:
Long time1 = System.currentTimeMillis();
for(int i = 0 ; i < 100000000 ;i++){
sum += arrays[i%10];
}
Long time2 = System.currentTimeMillis();
System.out.println("数组求和所花费时间:" + (time2 - time1) + "毫秒");
Long time3 = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
sum += list.get(i%10);
}
Long time4 = System.currentTimeMillis();
System.out.println("List求和所花费时间:" + (time4 - time3) + "毫秒");
--------------Output:
数组求和所花费时间:696毫秒
List求和所花费时间:3498毫秒
从上面的时间消耗上面来说数组对于基本类型的求和计算的速度是集合的5倍左右。其实在list集合中,求和当中有一个致命的动作:list.get(i)。这个动作是进行拆箱动作,Integer对象通过intValue方法自动转换成一个int基本类型,在这里就产生了不必要的性能消耗。
所以在性能要求较高的场景中请优先考虑数组。
数组的扩容: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;
//拷贝数组,生成新的数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
数组转换为list
我们经常需要使用到Arrays这个工具的asList()方法将其转换成列表。方便是方便,但是有时候会出现莫名其妙的问题。如下:
public static void main(String[] args) {
int[] datas = new int[]{1,2,3,4,5};
List list = Arrays.asList(datas);
System.out.println(list.size());
}
------------Output:
结果是1,是的你没有看错, 结果就是1。但是为什么会是1而不是5呢?先看asList()的源码
public static <T> List<T> asList(T... a) {
return new ArrayList<T>(a);
}
注意这个参数:T…a,这个参数是一个泛型的变长参数,我们知道基本数据类型是不可能泛型化的,也是就说8个基本数据类型是不可作为泛型参数的,但是为什么编译器没有报错呢?这是因为在java中,数组会当做一个对象来处理,它是可以泛型的,所以我们的程序是把一个int型的数组作为了T的类型,所以在转换之后List中就只会存在一个类型为int数组的元素了。所以我们这样的程序System.out.println(datas.equals(list.get(0)));输出结果肯定是true。当然如果将int改为Integer,则长度就会变成5了 public static void main(String[] args) {
// TODO Auto-generated method stub
Integer[] datas = new Integer[] { 1, 2, 3, 4, 5 };
List list = Arrays.asList(datas);
System.out.println(list.size());
System.out.println(list);
}
运行结果:
5
[1, 2, 3, 4, 5]
我们在看下面程序:
enum Week{Sum,Mon,Tue,Web,Thu,Fri,Sat}
public static void main(String[] args) {
Week[] weeks = {Week.Sum,Week.Mon,Week.Tue,Week.Web,Week.Thu,Week.Fri};
List<Week> list = Arrays.asList(weeks);
list.add(Week.Sat);
}
这个程序非常简单,就是讲一个数组转换成list,然后改变集合中值,但是运行呢?
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:131) at java.util.AbstractList.add(AbstractList.java:91) at com.array.Test.main(Test.java:18)编译没错,但是运行竟然出现了异常错误!UnsupportedOperationException ,当不支持请求的操作时,就会抛出该异常。从某种程度上来说就是不支持add方法,我们知道这是不可能的!什么原因引起这个异常呢?先看asList()的源代码:
public static <T> List<T> asList(T... a) {
return new ArrayList<T>(a);
}
这里是直接返回一个ArrayList对象返回,但是注意这个ArrayList并不是java.util.ArrayList,而是Arrays工具类的一个内之类:private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
if (array==null)
throw new NullPointerException();
a = array;
}
/** 省略方法 **/
}
但是这个内部类并没有提供add()方法,那么查看父类:public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
这里父类仅仅只是提供了方法,方法的具体实现却没有,所以具体的实现需要子类自己来提供,但是非常遗憾
这个内部类ArrayList并没有提高add的实现方法。在ArrayList中,它主要提供了如下几个方法:
1、size:元素数量
2、toArray:转换为数组,实现了数组的浅拷贝。
3、get:获得指定元素。
4、contains:是否包含某元素。
所以综上所述,asList返回的是一个长度不可变的列表。数组是多长,转换成的列表是多长,我们是无法通过add、remove来增加或者减少其长度的。
怎么解决这个问题呢? public static void main(String[] args) {
// TODO Auto-generated method stub
Integer[] datas = new Integer[] { 1, 2, 3, 4, 5 };
List list = Arrays.asList(datas);
ArrayList<Integer> arr=new ArrayList<Integer>(list);
arr.add(6);
System.out.println(list.size());
System.out.println(list);
System.out.println(arr.size());
System.out.println(arr);
}
运行结果:
5
[1, 2, 3, 4, 5]
6
[1, 2, 3, 4, 5, 6]