今天在看Holding Your Object这一样,这一章初步讲解Java中的容器类。在这里,我也按照书上讲的顺序介绍容器,部分是书上讲的,自己觉得比较重要的;部分是自己的体会。
- ArrayList
- Arrays.asList()
- ArrayList是我们在Java中使用的比较频繁的一个类(起码是我使用比较频繁的一个。)当我们在创建这个类的时候,我们可以制定里面到底是存放什么类型的数据,这样能给我们编程带来很多的方面。因为如果放入的类型不是指定的类型或者其子类的话,在编译的时候就会出现错误。这些其实是泛型的内容。
- ArrayList是一个容器,所以能够动态的扩展。在这里讲讲ArrayList的初始大小,以及如何扩展的。
初始大小,ArrayList中有三个构造函数:
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "
+ initialCapacity);
this.elementData = new Object[initialCapacity];
}
上面这个构造函数,是在申明的时候定义了初始的大小。
public ArrayList() {
this(10);
}
当我们使用一个没有参数的构造函数,初始的大小是10.
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
另外,也可以直接使用Collection来初始化这个ArrayList,这样ArrayList的初始大小就是这个Collection的大小。
如何扩展的呢?
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);
}
}
上面的代码,是在ArrayList执行add或者addAll操做前要先执行的一个函数,minCapacity是增加后,最小需要的容量。如果当前容量足够的话,就不增加,如果不够的话,就会按照oladCapacity * 23 / 2 + 1的方式来扩充容量。如果扩充之后还是不够的话,就直接按照minCapacity。在扩充的过程中,我们也发现,会使用较大的内存,这个是Arrays.copyOf的实现了。
- ArrayList到array的转化
在ArraList中,有一个toArray的方法,可以把ArrayList直接转化成array。toArray()这个方法有重载函数。
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
toArray(),就直接返回一个Object的数组。
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 > siz
a[size] = null;
return a;
}
toArray(T[] a)会返回一个对应类型的数组。但是在这里,我们需要注意的是,当a中的容量足以存放这个ArrayList的时候,就直接放到了a数组里,所以会修改a数组的值。但是如果不够的话,就直接copy成一个数组,这样a数组是不会变化的。
- ArrayList中是不能进行向上转化的
先上例子,然后慢慢解释。
class A{
}
class B extends A{
}
public class ArrayListTest {
public static void main(String args[]) {
List<A> arraya = new ArrayList<A>();
//List<A> arrayb = new ArrayList<B>();
//exception Type mismatch: cannot convert from ArrayList<B> to List<A>
A[] a;
B[] b = new B[0];
a = b;
}
}
在上面的代码中,我们看到,虽然B是A的子类,但是ArrayList<B>不能转化到ArrayList<A>,但是数组是可以的。在这个基础上,就能比较好的理解书中的一个例子了。
class Snow {
}
class Powder extends Snow {
}
class Light extends Powder {
}
class Heavy extends Powder {
}
class Crusty extends Snow {
}
class Slush extends Snow {
}
public class AsListInference {
public static void main(String[] args) {
List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(),
new Powder());
// Won’t compile:
// List<Snow> snow2 = Arrays.asList(
// new Light(), new Heavy());
// Compiler says:
// found : java.util.List<Powder>
// required: java.util.List<Snow>
List<Snow> snow2 = Arrays.asList(new Light(), new Heavy(),
new Powder(), new Crusty());
List<Snow> snow3 = new ArrayList<Snow>();
Collections.addAll(snow3, new Light(), new Heavy());
// Give a hint using an
// explicit type argument specification:
List<Snow> snow4 = Arrays.<Snow> asList(new Light(), new Heavy());
}
}
Arrays.asList
Arrays.asList的实现如下:
public static <T> List<T> asList(T... a) {
return new ArrayList<T>(a);
}
当我看到上面代码的时候,我就认为就是使用a来构造一个新的ArrayList。但是下面的代码就会让你非常的疑惑。
public class AddingGroups {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
list.set(1, 99); // OK -- modify an element
// list.add(21); // Runtime error because the
// underlying array cannot be resized.
// java.lang.UnsupportedOperationException
}
}
上面代码注释的地方,竟然不能使用add的方法。所以自己看Arrays的实现,我们会发现,Arrays.toList中使用到的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;
}
这个内部的ArrayList类中,并没有实现add的方法。所以才会出现上面的exception。