集合和数组都是对多个数据进行存储操作的结构,简称Java容器。
注意:此时的存储是内存层面的存储,而非持久化的存储。
1.2数组存储的特点与缺点数组存储的特点:1)一旦初始化之后,其长度就确定了;2)数组一旦定义好,其元素的类型也就确定了,我们也就只能操作指定类型的数据。
数组存储的缺点:1)一旦初始化之后,其长度就不可修改;2)数组中提供的方法十分有限;3)若想获取数组中实际元素的个数,没有现成的属性和方法可用;4)数组存储的是有序、可重复的数据,无法满足无序、不可重复数据的存储需求。
1.3集合框架Java集合可分为Collection体系和Map体系
<1>Collection接口:单列数据,定义了存取一组对象的方法的集合
1)List接口:元素有序,可重复的集合,(习惯上称为“动态数组” );→常用实现类:ArrayList,linkedArrayList,Vector。
2)Set接口:元素无序,不可重复的集合;→常用实现类:HashSet,linkedHashSet,TreeSet。
3)Quene接口。
<2>Map接口:双列数据,保存具有映射关系的“key-value对”的集合。→常用实现类:HashMap,linkedHashMap,TreeMap,Hashtable,Properties。
2.Collection接口常用的方法注意:向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class CommonlyUsedMethod
{
public static void main(String[] args)
{
Collection coll=new ArrayList();
System.out.println("1.add(Object e)的使用");
coll.add(1234);
coll.add("aaa");
System.out.println("2.size()的使用");
System.out.println(coll.size());//输出2
System.out.println("3.addAll(Collection coll)的使用");
Collection coll2=new ArrayList();
coll2.addAll(coll);
coll2.add(5678);
System.out.println(coll2.size());//输出3
System.out.println(coll2);//输出集合coll2中的元素:[1234, aaa, 5678]
System.out.println("4.isEmpty()的使用");
System.out.println(coll2.isEmpty()); //输出false
System.out.println("5.clear()的使用");
coll.clear();
coll2.clear();
System.out.println("6.contains(Obkect o)的使用");
coll2.add(123);coll2.add(456);coll2.add(true);coll2.add(new String("Tom"));
System.out.println(coll2.contains(123));//输出true
System.out.println(coll2.contains(new String("Tom"))); //输出true,这里其实又造了一个String对象,由此可见查看是否包含有元素,调的是当前类的equals()方法
System.out.println("7.containsAll(Collection coll)的使用");
coll.add(123);coll.add(true);
System.out.println(coll2.containsAll(coll)); //输出true
System.out.println("8.remove(Object o)的使用");
System.out.println(coll2); //输出[123, 456, true, Tom]
System.out.println(coll2.remove(456)); //输出true
System.out.println(coll2); //输出[123, true, Tom]
System.out.println("9.removeAll(Collection coll)的使用");
System.out.println(coll); //输出[123, true]
coll2.removeAll(coll);
System.out.println(coll2);//输出Tom
System.out.println("10.retainAll(Collection coll)的使用");
coll.add(456);coll.add(789);
System.out.println(coll);//coll为:[123, true, 456, 789]
coll2.add(456);coll2.add(789);
System.out.println(coll2);//coll2为:[Tom, 456, 789]
System.out.println(coll2.retainAll(coll));//输出true
System.out.println(coll2);//此时,coll2为:[456, 789]
System.out.println("11.equals(Object o)的使用");
Collection coll3=new ArrayList();
coll3.add(456);coll3.add(789);
System.out.println(coll2.equals(coll3));//输出true
Collection coll4=new ArrayList();
coll4.add(789);coll4.add(456);
System.out.println(coll2.equals(coll4));//输出false,因为这里ArrayList需要有序
System.out.println("12.hashcode()的使用");
System.out.println(coll2.hashCode());//输出15886
System.out.println("13.toArray()的使用");
Object[] arr=coll2.toArray();
for (Object o: arr)
{
System.out.println(o);//遍历输出数组arr中的(其实也是coll2中的)的元素
}
System.out.println("14.Array中的asList方法");
String[] strs=new String[]{"qwer","tyui","asdf"};
List strings = Arrays.asList(strs);
System.out.println(strings);
}
}
3.集合元素的遍历
3.1使用迭代器Iterator接口遍历集合
<1>迭代器模式
访问容器对象中的各个元素,而又不暴露该对象的内部细节,主要用于遍历Collection中的元素。
iterator()仅用于遍历集合,且集合对象每次调用iterator(),都会得到一个全新的迭代器对象,默认游标在集合的第一个元素之前。
<2>迭代器的hasNext()和next()方法
hasNext():boolean→以当前位置为基础,判断下一位置是否还有元素
next():E→指针下移,并将下移以后集合位置上的元素返回。
代码:
对于代码中的“Iterator iterator=coll.iterator();”这一句,是因为集合中的iterator()方法返回的是Iterator接口的对象,其实际过程为:ArrayList实现类中定义了一个内部类Itr,Itr实现了Iterator接口,即“private class Itr implemens Iterator
@Test
public void nextAndhasNextTest()
{
Collection coll = new ArrayList();
coll.add(123);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);
Iterator iterator = coll.iterator();
while (iterator.hasNext())
{
System.out.println(iterator.next());
}
}
<3>一种用迭代器遍历集合的错误示范
//下面这样写会出现错误,陷入死循环,不断输出集合的第一个元素123
//原因是因为:集合对象每次调用iterator()方法都得到一个全新的迭代器对象!!
// while(coll.iterator().hasNext())
// {
// System.out.println(coll.iterator().next());
// }
<4>迭代器的remove()方法(注意这是迭代器哦的remove方法)
remove():void →删除当前迭代器所在位置的元素
注意:如果还未调用next()或在上一次调用next()方法后已经调用了remove()方法,再调用remove()都会报IIlegalStateException异常。
@Test
public void removeTest()
{
Collection coll = new ArrayList();
coll.add(123);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);
Iterator iterator1 = coll.iterator();
while (iterator1.hasNext())
{
Object o = iterator1.next();
if ("Tom".equals(o))
{
iterator1.remove();
}
}
iterator1=coll.iterator();//因为上面的while循环使得iterator1指向了最后的位置,所以这里重置一下
while (iterator1.hasNext())
{
System.out.println(iterator1.next());
}
}
3.2使用增强for循环遍历集合
<1>快捷键:集合名.for 或者 iter
<2>格式: for(集合中元素的类型 局部变量名:集合对象名) {......}
<3>其内部实质上仍调用了迭代器
<4>增强for循环不会改变原有集合中元素的值
4.Collection子接口之——List接口 4.1List接口概述<1>List集合类中元素有序,且可重复,每个元素都有其对应的顺序索引;
<2>List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素;
<3>List接口的三个常用类:ArrayList,linkedList,Vector的异同
同:都实现了List接口,存储数据的特点相同:即有序,可重复的数据
异:1)ArrayList:线程不安全,效率高,底层使用Object[] elementData存储;2)linkedList:对于频繁地插入、删除操作,使用linkedList比使用ArrayList的效率要高,底层使用双向链表存储;3)Vector:是List接口的古老实现类,线程安全,效率低,底层使用Object[] elemenData存储。
4.2ArrayList源码分析ArrayList底层使用了数组Object[] elementData
<1>▲▲jdk7情况下:
1)就ArrayList的初始化而言,ArrayList list=new ArrayList() //底层创建了长度是10的Object[]数组,数组名为elementData
具体情况为:ArrayList.java中存在代码:
private transient Object[] elementData;
public ArrayList (int initialCapacity)
{
super();
if(initialCapacity<0)
throw new IllegalArgumentException("Illegal Capacity:"+initialCapacity);
this.elementData=new Object[initialCapacity];
}
public ArrayList()
{this(10);}//当使用空参构造器造ArrayList对象时,定义了一个容量为10的Object型数组
2)就ArrayList添加元素而言
list.add(1); //相当于elementData[0]=new Integer(1);
.......................
list.add(11);// 若此次的添加导致底层的elementData数组容量不够,则需扩容,默认情况下扩容为原来的1.5倍。同时,需将原有数组中的数据复制到新的数组中。
结论:建议开发中使用带参的构造器
<2>▲▲jdk8情况下
ArrayList list=new ArrayList(); //底层Object[] elementData初始化为{},并没有创建长度为10的数组
list.add(1);// 当第一次调用add()方法时,底层才创建了长度为10的数组,并将数据1添加到elementData数组的第一个位置上,后续的添加与扩容与jdk7无异。
<3>jdk7中ArrayList对象的创建类似于单例模式的饿汉式,而jdk8中ArrayList对象的创建类似于单例模式的懒汉式,这延迟了数组的创建,节省了内存。
4.3linkedList源码分析linkedList list=new linkedList(); //内部声明了Node类型的first和last属性,默认值为null
list.add(123); //将123封装到Node中,创建了Node对象
其中,Node定义为:
private static class Node{ E item; Node next; Node prev; Node(Node prev,E element,Node next) { this.item=element; this.next=next; this.prev=prev; } }



