注意:
①、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。
②、集合存放的是多个对象的引用,对象本身还是放在堆内存中。
③、集合可以存放不同类型,不限数量的数据类型。
二:集合的框架:
三:集合详解
1:Collection接口
Collection接口是List,Set,Queue接口的父接口。
下面是一个Collection集合使用的例子:
import java.util.*;
public class CollectionTest {
public static void main(String[] args)
{
Collection c = new ArrayList();
//添加元素
c.add("孙悟空");
c.add(6);//自动装箱
c.add("Java");
System.out.println("c集合的元素个数为:"+c.size()); //输出2
//删除指定元素
c.remove(6);
System.out.println("c集合的元素个数为:"+c.size()); //输出1
//判断是否包含指定字符串
System.out.println("c集合是否包含\"孙悟空\"字符串:"
+c.contains("孙悟空")); //输出true
c.add("猪八戒");
System.out.println("c集合的元素" + c);
Collection books = new HashSet();
books.add("数学");
books.add("Java");
System.out.println("c集合是否完全包含books集合?"
+ c.containsAll(books)); //输出false
//用c集合减去books集合里的元素
c.removeAll(books);
System.out.println("c集合的元素" + c);
//删除c集合里面所有的元素
c.clear();
System.out.println("c集合的元素" + c);
//控制books集合里只剩下c集合里也包含的元素
books.retainAll(c);
System.out.println("books集合的元素:" + books);
}
}
运行结果:
把运行结果和代码结合来看,可以看出Collection的用法有:添加元素、删除元素、返回Collection集合的元素个数以及清空整个集合等。
2:Iterator接口:
Iterator接口也是Java集合框架的成员,但它与Collection系列、Map系列的集合不一样:Collection系列集合、Map系列集合主要用于盛装其他对象,而Iterator则主要用于遍历(即迭代访问)Collection集合中的元素,Iterator对象也被称为迭代器。
Iterator接口里定义了如下3个主要方法:
Object next():返回迭代器刚越过的元素的引用,返回值是 Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
下面程序示范了通过Iterator接口来遍历集合元素:
import java.util.*;
public class Iteratortest {
public static void main(String[] args)
{
//创建一个集合
Collection books = new HashSet();
books.add("数学");
books.add("语文");
books.add("英语");
//获取books集合对应的迭代器
Iterator it = books.iterator();
while(it.hasNext())
{
//it.next()方法返回的数据类型是Object类型,所以要强制转换
String book = (String)it.next();
System.out.println(book);
if(book.equals("语文"))
{
//从集合中删除上一次next()方法返回的元素
it.remove();
}
}
System.out.println(books);
}
}
注意:1:Iterator接口必须依附于Collection接口,若有一个Iterator对象,则必然有一个与之关联的Collection对象。
2:当使用Iterator迭代器访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过Iterator的remove()方法删除上一次next()方法返回的集合元素才可以。
3:Set集合
Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。
(1) HashSet:Set接口的典型实现。HashSet按Hash算法来存储集合中的元素,因此具有很好的存储和查找性能。
①、HashSet:不能保证元素的顺序;不可重复;不是线程安全的;集合元素可以为 NULL;
①、不可以重复,有序
因为底层采用链表和哈希表的算法。链表保证元素的添加顺序,哈希表保证元素的唯一性
TreeSet:有序;不可重复,底层使用 红黑树算法,擅长于范围查询。
* 如果使用 TreeSet() 无参数的构造器创建一个 TreeSet 对象, 则要求放入其中的元素的类必须实现 Comparable 接口所以, 在其中不能放入 null 元素
* 必须放入同样类的对象.(默认会进行排序) 否则可能会发生类型转换异常.我们可以使用泛型来进行限制
下面程序测试了TreeSet的通用用法
import java.util.*;
public class TreeSetTest {
public static void main(String[] args)
{
TreeSet nums = new TreeSet();
//向TreeSet中添加四个Integer对象
nums.add(5);
nums.add(2);
nums.add(10);
nums.add(-9);
//输出集合元素,看到集合元素已经处于排序状态
System.out.println(nums);
//输出第一个元素
System.out.println(nums.first());
//输出最后一个元素
System.out.println(nums.last());
//返回小于4的子集
System.out.println(nums.headSet(4));
//返回大于5的子集,如果Set中包含5,子集中还包含5
System.out.println(nums.tailSet(5));
}
}
下面是运行结果:
从上面程序的运行结果可以看出,TreeSet并不是根据元素的插入顺序进行排序的,而是根据元素的实际值的大小进行排序的。
自然排序:
添加自定义对象的时候,必须要实现 Comparable 接口,并要覆盖 compareTo(Object obj) 方法来自定义比较规则
如果 this > obj,返回正数 1
如果 this < obj,返回负数 -1
如果 this = obj,返回 0 ,则认为这两个对象相等
注意:向TreeSet中添加的应该是同一类对象
import java.util.*;
public class TreeSetTest {
public static void main(String[] args) {
Person p1 = new Person(20);
Person p2 = new Person(35);
Person p3 = new Person(18);s
Set<Person> set = new TreeSet<>(new Person());
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set); //结果为[18, 20, 35]
}
}
class Person implements Comparator<Person>{
public int age;
public Person(){}
public Person(int age)
{
this.age = age;
}
@Override
/***
* 根据年龄大小进行排序
*/
public int compare(Person o1, Person o2)
{
if(o1.age > o2.age)
{
return 1;
}
else if(o1.age < o2.age)
{
return -1;
}
else
{
return 0;
}
}
@Override
public String toString()
{
return ""+this.age;
}
}
定制排序:
创建 TreeSet 对象时, 传入 Comparator 接口的实现类. 要求: Comparator 接口的 compare 方法的返回值和 两个元素的 equals() 方法具有一致的返回值
4:List集合
List集合代表一个有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合默认按添加顺序设置元素的索引。 所有的List中可以有null元素
1、List 接口的三个典型实现:
①、List list1 = new ArrayList();底层数据结构是数组,查询快,增删慢;线程不安全,效率高
②、List list2 = new Vector();
底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合
③、List list3 = new LinkedList();
底层数据结构是链表,查询慢,增删快;线程不安全,效率高
下面程序示范了List集合的常规用法
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args)
{
List books = new ArrayList();
//向books集合中添加三个元素
books.add("语文");
books.add("数学");
books.add("英语");
System.out.println(books);
//将新字符串对象插入在二个位置
books.add(1 , new String("Java"));
for(int i = 0 ; i < books.size() ; i++)
{
System.out.println(books.get(i));
}
//删除第三个元素
books.remove(2);
System.out.println(books);
//判断指定元素在List集合中的位置,输出0,表示在第一位
System.out.println(books.indexOf(new String("语文")));
//将第二个元素替换成新的字符串对象
books.set(1, new String("C语言"));
System.out.println(books);
//将books集合的第二个元素(包括)到第三个元素(不包括)截取成子集合
System.out.println(books.subList(1 , 2));
}
}
Array.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可以增加、删除该集合里的元素。
LinkedList:LinkedList是List集合,但它还实现了Deque接口,可以被当作双端队列来使用,因此既可以被当成”栈“来使用,也可以当成队列来使用
下面程序简单示范了LinkedList集合的用法:
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args)
{
LinkedList books = new LinkedList();
//将字符串元素加入队列的尾部
books.offer("语文");
//将一个字符串元素加入栈的顶部
books.push("数学");
//将字符串元素添加到队列的头部(相当于栈的顶部)
books.offerFirst("英语");
//以List的方式(按索引访问的方式)来遍历集合元素
for(int i = 0; i < books.size() ; i++)
{
System.out.println("遍历中: "+ books.get(i));
}
//访问并不删除栈顶元素
System.out.println(books.peekFirst());
//访问并不删除队列的最后一个元素
System.out.println(books.peekLast());
//将栈顶元素弹出“栈”
System.out.println(books.pop());
System.out.println(books);
//访问并删除队列的最后一个元素
System.out.println(books.pollLast());
//输出数学
System.out.println(books);
}
}
5:Map集合:
一个键(key)和它对应的值构成map集合中的一个元素。
Map中的元素是两个对象,一个对象作为键,一个对象作为值。键不可以重复,但是值可以重复。
1、严格来说 Map 并不是一个集合,而是两个集合之间 的映射关系。
2、这两个集合没每一条数据通过映射关系,我们可以看成是一条数据。即 Entry(key,value)。Map 可以看成是由多个 Entry 组成。
3、因为 Map 集合即没有实现于 Collection 接口,也没有实现 Iterable 接口,所以不能对 Map 集合进行 for-each 遍历。
下面程序示范了Map的基本功能:
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args)
{
Map map = new HashMap();
map.put("语文", 109);
map.put("数学",10);
map.put("英语", 79);
//value可以重复
map.put("Java", 109);
System.out.println(map);
//判断是否含有指定key
System.out.println("是否包含值为 语文 key:"+map.containsKey("语文")); //输出true
//判断是否包含指定value
System.out.println("是否包含值为 109 value: "+ map.containsValue(109)); //输出true
//获取Map集合的所以key组成的集合,通过遍历key来实现遍历所以的key-value对
for(Object key : map.keySet() )
{
//map.get(key)方法获取指定key对应的value
System.out.println(key + "-->" + map.get(key));
}
map.remove("数学");
System.out.println(map);
}
}
1:HashMap:
线程不安全,效率高。允许null键和null值
是基于哈希表的Map接口实现。哈希表的作用是用来保证键的唯一性的。
常用实例化方法:
new HashMap< Object, Object>();
2:Hashtable:
线程安全,效率低。不允许null键和null值
类似于HashSet,HashMap、Hashtable判断两个key相等的标准也是:两个key通过equals()方法比较返回true,两个key的hashCode值也相等。
HashMap、Hashtable判断两个value相等的标准更简单:只要两个对象通过equals()方法比较返回true即可。
是基于Map接口的哈希表和链接列表实现,有序
由哈希表保证键的唯一性
由链表保证键盘的有序(存储和取出的顺序一致)
常用实例化方法:
new LinkedHashMap< Object, Object>();
构造方法:
TreeMap() 使用键的自然顺序构造一个新的、空的树映射。
TreeMap(Comparator< ? super K> comparator) 构造一个新的、空的树映射,该映射根据给定比较器进行排序