集合框架
简介
集合的由来
数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少
定义:
java提供了一种可以存数一组数据的数据结构,其提供了丰富的方法,在实际开发中往往比数组使用的广泛。这种数据结构成为集合:Collection。
Collection是一个接口,其定义了集合的相关功能方法。
数组和集合的区别
- 区别1 :
- 数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值
- 集合只能存储引用数据类型(对象)集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象
- 区别2:
- 数组长度是固定的,不能自动增长
- 集合的长度的是可变的,可以根据元素的增加而增长
数组和集合什么时候用
- 如果元素个数是固定的推荐用数组
- 如果元素个数不是固定的推荐用集合
集合框架图
Collection (集合的最大接口)继承关系
——List 可以存放重复的内容
——Set 不能存放重复的内容,所以的重复内容靠hashCode()和equals()两个方法区分
——Queue 队列接口
——SortedSet 可以对集合中的数据进行排序
关于list,set,map的我的博客链接java集合(list,set,map)
Collection定义了集合框架的共性功能。
Collection接口常见的方法
(1)单元素添加、删除操作。
方法 | 描述 |
---|---|
boolean add(Object o) | 将对象添加给集合。 |
boolean remove(Object o) | 如果集合中有与o相匹配的对象,则删除对象o。 |
(2)查询操作。
方法 | 描述 |
---|---|
int size() | 返回当前集合中元素的数量。 |
boolean isEmpty() | 判断结合中是否有任何元素。 |
boolean contains(Object o) | 查找集合中是否含有元素o。 |
Iterator iterator() | 返回一个迭代器,用来访问集合中的各个元素。 |
(3)组操作:作用于元素或整个结合。
方法 | 描述 |
---|---|
boolean containsAll(Collection c) | 查找集合中是否含有集合c中的所有元素。 |
boolean addAll(Collectiion c) | 将集合c中的所有元素添加给该集合。 |
void clear() | 删除集合中所有的元素。 |
void removeAll(Collection c) | 从集合中删除集合c中的所有元素。 |
void retainAll(Collection c) | 从集合中删除集合c中不包含的元素。 |
(4)Collection转换为Object数组。
方法 | 描述 |
---|---|
Object[] toArray() | 返回一个内含集合所有元素的数组。 |
Object[] toArray(Object[] a) | 返回一个内含集合所有元素的数组。运行期返回的数组和参数a的类型相同。 |
注:集合中存储的都是对象的引用(地址)
Iterator 迭代器
Collection提供了一个遍历集合的通用方式,迭代器(Iterator)。
获取迭代器的方式是使用Collection定义的方法:
Iterator iterator():迭代器Iterator是一个接口,集合在覆盖Collection的iterator()方法时提供了迭代器的实现。Iterator提供了统一的遍历集合元素的方式。
迭代器原理
迭代器原理:迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么就需要在每一个类中定义hasNext()和next()方法,这样做是可以的,但是会让整个集合体系过于臃肿,迭代器是将这样的方法向上抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做的好处有二:
第一规定了整个集合体系的遍历方式都是hasNext()和next()方法;
第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可
hasNext与next方法
迭代器用于遍历集合的两个主要方法:
boolean hasNext():判断集合是否还有元素可以遍历。
E next():返回迭代的下一个元素
遍历集合应遵循“先问后取”的方式,也就是说,应当在确定hasNext()方法的返回值为true的情况下再通过next()方法取元素。
由此可以看出,使用迭代器遍历集合是通过boolean值驱动的,所以它更适合使用while循环来遍历。
Collection<String> c = new HashSet<String>();
c.add("java");
c.add("cpp");
c.add("php");
c.add("c#");
c.add("objective-c");
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
remove方法
迭代器还提供了一个方法:
void remove()该方法用于删除迭代器当次从集合中获取的元素。若我们在迭代过程中想删除集合元素时,我们就需要通过该方法来进行。这里需要注意,在使用迭代器遍历集合时是不能通过集合自身提供的remove方法删除元素的,否则迭代器在迭代时会抛出异常。
Collection<String> c = new HashSet<String>();
c.add("java");
c.add("cpp");
c.add("php");
c.add("c#");
c.add("objective-c");
System.out.println(c); // [cpp, php, c#, java, objective-c]
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String str = it.next();
if (str.indexOf("c") != -1) {
it.remove();
}
}
System.out.println(c); // [php, java]
增强for循环
Java5.0之后推出了一个新的特性,增强for循环,也称为新循环。该循环不通用于传统循环的工作,其只用于便利集合或数组。 语法:
for(元素类型 e : 集合或数组){
循环体
}
新循环并非新的语法,而是在编译过程中,编译器会将新循环转换为迭代器模式。所以新循环本质上是迭代器。
例如:
Collection<String> c = new HashSet<String>();
c.add("java");
c.add("cpp");
c.add("php");
c.add("c#");
c.add("objective-c");
for (String str : c) {
System.out.print(str.toUpperCase() + " ");
}
// CPP PHP C# JAVA OBJECTIVE-C
泛型机制
泛型在集合中的应用
泛型是Java SE 5.0引入的特性,泛型的本质是参数化类型。在类、接口和方法的定义过程中,所操作的数据类型被传入的参数指定。
Java泛型机制广泛的应用在集合框架中。所有的集合类型都带有泛型参数,这样在创建集合时可以指定放入集合中的对象类型。Java编译器可以据此进行类型检查,这样可以减少代码在运行时出现错误的可能性。
我们来举个例子,比如ArrayList,其在定义时是这样的:
public class ArrayList<E> {
… … …
public boolean add(E e) {…};
public E get(int index) {…};
}
由此我们可以看出,再声明ArrayList时,类名的右侧有一个。”<>”表示泛型,而其中可以使用数字字母下划线(数字不能的第一个字符)来表示泛型的名字。(通常我们使用一个大写字母来表示,当然这个不是规定。)这时,在类中声明的方法的参数,返回值类型可以被定义为泛型。这样在创建对象时可以将类型作为参数传递,此时,类定义所有的E将被替换成传入的参数。
例如:
ArrayList<String> list = new ArrayList<String>();//泛型E在这里被指定为String类型
list.add("One");//那么add方法的参数就被替换为String类型
list.add(100);//这里就会出现编译错误,因为这里的参数应为String类型。
集合工具类
Collections:集合框架的工具类。里面定义的都是静态方法。
Collections和Collection有什么区别?
Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
它有两个常用的子接口,
List:对元素都有定义索引。有序的。可以重复元素。
Set:不可以重复元素。无序。
Collections是集合框架中的一个工具类。该类中的方法都是静态的。
提供的方法中有可以对list集合进行排序,二分查找等方法。
通常常用的集合都是线程不安全的。因为要提高效率。
如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
常用的方法
排序操作(主要针对List接口相关)
方法 | 描述 |
---|---|
reverse(List list) | 反转指定List集合中元素的顺序 |
shuffle(List list) | 对List中的元素进行随机排序(洗牌) |
sort(List list) | 对List里的元素根据自然升序排序 |
sort(List list, Comparator c) | 自定义比较器进行排序 |
swap(List list, int i, int j) | 将指定List集合中i处元素和j出元素进行交换 |
rotate(List list, int distance)|将所有元素向右移位指定长度,如果distance等于size那么结果不变|
例子
public void testSort() {
System.out.println("原始顺序:" + list);
Collections.reverse(list);
System.out.println("reverse后顺序:" + list);
Collections.shuffle(list);
System.out.println("shuffle后顺序:" + list);
Collections.swap(list, 1, 3);
System.out.println("swap后顺序:" + list);
Collections.sort(list);
System.out.println("sort后顺序:" + list);
Collections.rotate(list, 1);
System.out.println("rotate后顺序:" + list);
}
输出
原始顺序:[b张三, d孙六, a李四, e钱七, c赵五]
reverse后顺序:[c赵五, e钱七, a李四, d孙六, b张三]
shuffle后顺序:[b张三, c赵五, d孙六, e钱七, a李四]
swap后顺序:[b张三, e钱七, d孙六, c赵五, a李四]
sort后顺序:[a李四, b张三, c赵五, d孙六, e钱七]
rotate后顺序:[e钱七, a李四, b张三, c赵五, d孙六]
查找和替换(主要针对Collection接口相关)
方法 | 描述 |
---|---|
binarySearch(List list, Object key) | 使用二分搜索法,以获得指定对象在List中的索引,前提是集合已经排序 |
max(Collection coll) | 返回最大元素 |
max(Collection coll, Comparator comp) | 根据自定义比较器,返回最大元素 |
min(Collection coll) | 返回最小元素 |
min(Collection coll, Comparator comp) | 根据自定义比较器,返回最小元素 |
fill(List list, Object obj) | 使用指定对象填充 |
frequency(Collection Object o) | 返回指定集合中指定对象出现的次数 |
replaceAll(List list, Object old, Object new) | 替换 |
例子
public void testSearch() {
System.out.println("给定的list:" + list);
System.out.println("max:" + Collections.max(list));
System.out.println("min:" + Collections.min(list));
System.out.println("frequency:" + Collections.frequency(list, "a李四"));
Collections.replaceAll(list, "a李四", "aa李四");
System.out.println("replaceAll之后:" + list);
// 如果binarySearch的对象没有排序的话,搜索结果是不确定的
System.out.println("binarySearch在sort之前:" + Collections.binarySearch(list, "c赵五"));
Collections.sort(list);
// sort之后,结果出来了
System.out.println("binarySearch在sort之后:" + Collections.binarySearch(list, "c赵五"));
Collections.fill(list, "A");
System.out.println("fill:" + list);
}
输出
给定的list:[b张三, d孙六, a李四, e钱七, c赵五]
max:e钱七
min:a李四
frequency:1
replaceAll之后:[b张三, d孙六, aa李四, e钱七, c赵五]
binarySearch在sort之前:-4
binarySearch在sort之后:2
fill:[A, A, A, A, A]
同步控制
Collections工具类中提供了多个synchronizedXxx方法,该方法返回指定集合对象对应的同步对象,从而解决多线程并发访问集合时线程的安全问题。HashSet、ArrayList、HashMap都是线程不安全的,如果需要考虑同步,则使用这些方法。这些方法主要有:synchronizedSet、synchronizedSortedSet、synchronizedList、synchronizedMap、synchronizedSortedMap。
特别需要指出的是,在使用迭代方法遍历集合时需要手工同步返回的集合。
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized (m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
总结
List:add/remove/get/set。
1,ArrayList:其实就是数组,容量一大,频繁增删就是噩梦,适合随机查找;
2,LinkedList:增加了push/[pop|remove|pull],其实都是removeFirst;
3,Vector:历史遗留产物,同步版的ArrayList,代码和ArrayList太像;
4,Stack:继承自Vector。Java里其实没有纯粹的Stack,可以自己实现,用组合的方式,封装一下LinkedList即可;
5,Queue:本来是单独的一类,不过在SUN的JDK里就是用LinkedList来提供这个功能的,主要方法是offer/pull/peek,因此归到这里呢。
Set:add/remove。可以用迭代器或者转换成list。
1,HashSet:内部采用HashMap实现的;
2,LinkedHashSet:采用LinkedHashMap实现;
3,TreeSet:TreeMap。
Map:put/get/remove。
1,HashMap/HashTable:散列表,和ArrayList一样采用数组实现,超过初始容量会对性能有损耗;
2,LinkedHashMap:继承自HashMap,但通过重写嵌套类HashMap.Entry实现了链表结构,同样有容量的问题;
3,Properties:是继承的HashTable。
顺便说一下Arrays.asList,这个方法的实现依赖一个嵌套类,这个嵌套类也叫ArrayList!