Java集合框架位于java.util包中,提供了一套性能优良、使用方便的接口和类。Java集合框架共有三大类接口: List、Set、Map:
![](https://i-blog.csdnimg.cn/blog_migrate/0f195151b7b65ef0b6e36cb398db35a2.png)
List接口:
概念:一组对象的集合,容器,用来存储对象的,他解决了数组一旦声明长度就固定的这种局限。List 接口存储一组不唯一,有序(插入顺序)的对象。
分类:集合分为两大类,用接口来体现
- 两大接口Collection和Map,其中Collection接口下面还有list接口和map接口
List接口特点:存储有顺序、不唯一的对象
List接口常用实现类:Vector、Arraylist、LinkedList
1、Arraylist:底层是数组实现,是长度可变的动态数组,观察源码可发现当创建一个ArrayList对象时,其实就相当于new了一个长度为10的Object类型的数组,当加入新的元素的时候,数组长度变为:原来长度*3/2+1,ArrayList中元素有序、通过角标操作,从0开始,ArrayList遍历元素和随机访问元素的效率比较高(角标),插入、删除等操作频繁时性能低下。ArrayList类实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高。
常用方法包括:size(集合长度)、add(添加元素)、get(通过角标获得元素)、set(给指定角标添加元素)、remove(删除元素)
2、LinkedList:底层是链表实现,LinkedList类采用链表存储方式。插入、删除元素时效率比较高,查找效率较低。插入、删除操作频繁时,可使用LinkedList来提高效率,LinkedList额外提供对头部和尾部元素进行添加和删除操作的方法。
常用方法包括:addFirst、removeFirst、addLast、removeLast
3、Vector:底层也是基于数组实现
三个实现类的区别:
- Arraylist和LinkedList线程不同步:效率高
- Vector是线程安全的,用synchronized修饰的。效率低
ArrayList和LinkedList的使用场景:
ArrayList:
- 遍历元素和随机访问元素的效率比较高
- 插入、删除等操作频繁时性能低下
LinkedList:
- 插入、删除元素时效率较高
- 查找效率较低
集合遍历的集中方式:
- 1、普通for循环
- 2、增强for循环forEach
- 3、Iterator(迭代器) 中的hasnext() 和 next()方法
- 注意:迭代器是专门为集合而生,它存在的意义就是遍历集合,在迭代器中,一边遍历一边移除的时候,一定要用迭代器的remove()。
关于哈希算法:
http://www.cnblogs.com/jiewei915/archive/2010/08/09/1796042.html
package com.liudm.demo12;
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
//容器——数组
//集合存储的都是对象
List list = new ArrayList(); //底层:new了一个长度为10的object类型的数组
//ArrayList:长度可变组,遍历效率高
//数据加入是有序的,可重复
list.add(12); //12:int→Integer:基本数据和包装类自动转化
list.add("abc");
list.add("abca");
list.add(45.5f);
System.out.println(list.get(1)); //角标从零开始
System.out.println(list.size()); //数组:length,字符串:length()
System.out.println(list.remove(1)); //根据角标移除
list.remove("abca"); //根据内容移除
Integer n = 12;
list.remove(n); //根据内容移除
System.out.println(list);
System.out.println(list.isEmpty());
System.out.println(list.set(0, 22)); //更新
list.clear(); //清空,没有返回值,不能打印
System.out.println(list); //
}
}
package com.liudm.demo12;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo1 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(12);
list.add("abc");
list.add("abca");
list.add(45.5f);
// for (int i = 0; i < list.size(); i++) { //一种遍历
// System.out.println(list.get(i));
// }
// for (Object o : list) { //一种遍历
// System.out.println(o);
// }
//迭代器,判断是否有下一个元素
Iterator it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
System.out.println(o);
}
}
}
package com.liudm.demo12;
import java.util.LinkedList;
public class ListDemo2 {
public static void main(String[] args) {
//linkedlist:删除、添加效率高,便于查找
//链表查找,3和length比较,大于就在后面找,小就在前面找
LinkedList list = new LinkedList();
list.add(34); //
list.addFirst("12");
list.add(34);
list.addFirst("12");
list.add(34);
list.addFirst("12");
System.out.println(list.get(3)); //
}
}
实验:定义一个List对象,如下:
List <String>list = new ArrayList<String>();
在list中添加元素,java,linux,hadoop,hive
在list的第二个位置添加元素,mysql
用Iterator迭代器遍历打印list中元素
在打印时,将list中的mysql,修改为hbase
package com.liudm.demo12;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
List <String> list = new ArrayList<String>();
list.add("java");
list.add("linux");
list.add("hadoop");
list.add("hive");
list.add(1, "mysql");
Iterator it = list.iterator();
while (it.hasNext()) {
Object object = it.next();
if ("mysql".equals(object)) {
object = "hbase";
}
System.out.println(object);
}
}
}
参考源码:
package my.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List <String>list = new ArrayList<String>();
//在list中添加元素,java,linux,hadoop,hive
list.add("java");
list.add("linux");
list.add("hadoop");
list.add("hive");
//在list的第二个位置添加元素,mysql
list.add(1,"mysql");//因为集合角标从0开始,所以第二位置的角标是1
//查看集合长度
System.out.println(list.size());
//通过角标查看元素
System.out.println(list.get(2));
//遍历集合-普通for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//遍历集合-增强for循环
for (String str : list) {
System.out.println(str);
}
//迭代器
Iterator it = list.iterator();
while(it.hasNext()){ //判断是否有下一个元素
String o = (String) it.next(); //接收下一个元素
if(o.equals("mysql")){
o = "hbase";
}
System.out.print(o + " ");
}
}
}
练习1:定义一个List对象,如下
List <String>list = new ArrayList<String>();
在list中添加元素,nihao,wohao,dajiahao,nihao
在list的第二个位置添加元素,tahao
用Iterator迭代器遍历打印list中元素
在打印时,将list中的nihao,修改为nibuhao
package com.liudm.demo12;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test1 {
public static void main(String[] args) {
List <String>list = new ArrayList<String>();
list.add("nihao");
list.add("wohao");
list.add("dajiahao");
list.add("nihao");
list.add(1,"tahao");
//迭代器
Iterator <String> it = list.iterator();
while(it.hasNext()){
Object o = it.next();
if(o.equals("nihao")){
o = "nibuhao";
}
System.out.println(o + " ");
}
}
}
练习2:选择一个集合添加三个Person对象,把姓名相同和年龄的的人当做同一个人,禁止重复添加。
提示:
Person类中定义name和age属性,重写hashCode()方法和equals()方法,针对Person类的name和age属性进行比较,如果name相同,hashCode()方法的返回值相同,equals方法返回true。
Person类:
package com.liudm.demo12;
public class Person {
private String name;
private int age;
public int hashCode(){
return name.hashCode();
}
public boolean equals(Object object){
if (this == object) {
return true;
}
if (object == null) {
return false;
}
Person oth = (Person) object;
return oth.name.equals(this.name);
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
测试类:
package com.liudm.demo12;
import java.util.HashSet;
public class Test2 {
public static void main(String[] args) {
HashSet person = new HashSet();
Person p1 = new Person("Jobs",40);
Person p2 = new Person("Marry",25);
Person p3 = new Person("Jobs",41);
person.add(p1);
person.add(p2);
person.add(p3);
for (Object object : person) {
Person per = (Person) object;
System.out.println(per.getName() + " " + per.getAge());
}
person.clear(); //清空,做下一个测试
System.out.println();
Person pe1 = new Person("Jobs",40);
Person pe2 = new Person("Marry",25);
Person pe3 = new Person("Job",40);
person.add(pe1);
person.add(pe2);
person.add(pe3);
for (Object obj : person) {
Person pers = (Person) obj;
System.out.println(pers.getName() + " " + pers.getAge());
}
}
}
练习3:使用对象保存每个学员的信息,包括学号、姓名、三门课的成绩、平均成绩,使用集合存所有学员的信息,需要实现以下函数:
- 单个学员信息的录入;
- 显示所有学员信息;
- 排序;(按照平均成绩由大到小)
- 插入;(插入后保持有序)
- 删除;(删除后保持有序)
在主方法中调用以上函数,分别完成录入、排序、插入和删除功能,并显示排序前后的学员信息,以及插入删除后的学员信息
set接口:
Set接口存储一组唯一,无序的对象。无get()方法,无法使用普通for循环遍历,可以使用增强for循环或使用Iterator遍历。
Set接口——HashSet
- HashSet 是Set接口常用的实现类
- HashSet允许集合元素值为null
- HashSet不是同步的,如果多个线程同时访问,则必须通过代码来保证其同步
- 操作数据的方法与List类似,Set接口不存在get()方法
HashSet newsTitleSet = new HashSet();
NewTitle car = new NewTitle(1, "汽车", "管理员");
//增加元素
newsTitleSet.add(car);
//遍历集合
for(Object obj :newsTitleList){
NewTitle title=(NewTitle)obj;
System.out.println(title.getTitleName());
}
HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找功能。
HashSet中存储元素,HashSet会调用该对象的hashcode()方法来得到HashCode值,然后根据HashCode值决定改对象在HashSet中的存储位置。
HashSet中比较元素相等规则:
- equals比较相等
- hashCode()返回的值相等
注意:两个对象通过equals方法比较相等,HashCode比较不相等,则仍然能添加成功。
Set接口——TreeSet
TreeSet可以保证集合中的元素处于排序状态。
TreeSet支持两种排序方法:
- 自然排序(ASCII码)
- 定制排序
public static void main(String{} args) {
//测试一下数字
TreeSet<Integer> set = new TreeSet<Integer>();
//反向存储数据
for(int i = 10; i >= 1; i--){
set.add(i);
}
//如果add了相同的数据,是无效的,因为set集合不能重复元素
set.add(10);
//输出结果,可以看到数据为自然的数字排序
System.out.println(set);
//输出结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
EG:
![](https://i-blog.csdnimg.cn/blog_migrate/a1504018e5546286ff8afda2ea88c758.png)
TreeSet ts =new TreeSet();
ts.add(new Student("lisi02", 22));
ts.add(new Student("lisi007", 20));
ts.add(new Student("lisi09", 19));
ts.add(new Student("lisi11", 40));
ts.add(new Student("lisi16", 30));
ts.add(new Student("lisi16", 50));
ts.add(new Student("lisi16", 23));
TreeSet定制排序两种方式:
1.实现comparable接
- 在类上implement Comparable
- 重写compareTo()方法:在方法内定义比较算法, 根据大小关系, 返回正数负数或零
2.传入一个比较器(实现comparator)
注意:在使用TreeSet存储对象的时候, add()方法内部就会自动调用compareTo()方法进行比较, 根据比较结果使用二叉树形式进行存储。
Iterator接口:
Iterator接口表示对集合进行迭代的迭代器,专门实现集合的遍历。
方法:
- hasNext():判断是否存在另一个可访问的元素
- next():返回要访问的下一个元素
System.out.println("使用Iterator遍历,分别是:");
Iterator it = list.iterator();
while (it.hasNext()) { //当有元素时返回true
String name = (String)it.next(); //返回类型是Object
System.out.println(name);
}
map接口:
1、Java 中的 Map 接口 是和 Collection 接口 同一等级的集合根接口,它 表示一个键值对 (key-value) 的映射,我们通常使用接口的实现类来存储元素。Map的常用实现类如下图所示:
HashMap:是Map接口最常用的实现类。HashMap中的键不能重复,如果重复,键对应的值被覆盖了;HashMap中的键和值都可以为null;键如果不存在,拿到的是一个null;不支持线程同步,当有多个线程同时写HashMap,可能导致数据不一致,可以使用Collection的synchronizedMap方法使其同步
LinkedHashMap:LinkedHashMap内部是双向链表结构,这种数据结构保证了元素插入的顺序,支持线程同步。
TreeMap:TreeMap 是一个有序的key-value集合,它是基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。此外,TreeMap是非线程同步的。
2、Map 接口提供了三种角度来分析 Map:
- KeySet
- Values
- Entry
(1).KeySet
KeySet 是一个 Map 中键(key)的集合,可以通过 Map.keySet() 方法获得,以 Set 的形式保存,不允许重复,因此键存储的对象需要重写 equals() 和 hashCode() 方法。
(2).Values
Values 是一个 Map 中值 (value) 的集合,通过 Map.values() 方法获得,以 Collection 的形式保存,因此可以重复。
(3).Entry
Entry 是 Map 接口中的静态内部接口,表示一个键值对的映射,通过 Map.entrySet() 方法获得的是一组 Entry 的集合,保存在 Set 中,所以 Map 中的 Entry 也不能重复。
Entry 具有的方法:
getKey() , 获取这组映射中的键 key
getValue() , 获取这组映射中的值 value
setValue() , 修改这组映射中的值
hashCode() , 返回这个 Entry 的哈希值
equals() , 对比 key-value 是否相等
package com.liudm.demo12;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
//map:键值对
public class mapDemo {
public static void main(String[] args) {
HashMap map = new HashMap();
//map.put(key, value)
map.put("班长","张三");
map.put("班长1","张三1");
map.put("班长2","张三2");
map.put("班长2","张三22");
map.put(null,"张三"); //可以为null
System.out.println(map.get("班长2"));
System.out.println();
Set s = map.keySet(); //hashmap的key:HashSet
for (Object object : s) {
System.out.println(object);
}
System.out.println();
//map.values();
Collection values = map.values();
for (Object object : values) {
System.out.println(object);
}
}
}
package com.liudm.demo12;
import java.util.ArrayList;
import java.util.List;
public class DemoT {
public static void main(String[] args) {
int [] nus = {1,2,3};
//<> :泛型,集合泛型
List<String> list = new ArrayList<String>();
list.add("aa");
//list.add(123);
list.add("123");
}
}
练习:Map接口和HashMap练习
定义一个Map对象,如下
Map<String,String> map = newHashMap<String,String>();
在map中添加键值对(“1”,“xiaohong”)、(“2”,”xiaowang”)、(“3”,”xiaoli”)
将map中的键值对打印出来(提示:可以将key集合放到一个set中,定义Iterator遍历器取出set中的key,然后通过key的值在map中取出对应value值,并将这两个值打印出来)
package com.liudm.demo12;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test4 {
public static void main(String[] args) {
//Map需要导包
Map<String, String> map = new HashMap<String, String>();
map.put("1", "xiaohong");
map.put("2", "xiaowang");
map.put("3", "xiaoli");
Set set = map.keySet(); //Set需要导包
Iterator it = set.iterator(); //Iterator需要导包
while (it.hasNext()) {
Object obj = it.next();
Object object = map.get(obj);
System.out.println("key:" + obj + " value:" + object);
}
}
}
实验:完成map集合的数据存储和遍历
package com.liudm.demo12;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class mapTest {
public static void main(String[] args) {
//Map需要导包
Map<String, String> map = new HashMap<String, String>();
map.put("NO.1", "第一名");
map.put("NO.2", "第二名");
map.put("NO.3", "第三名");
map.put("NO.4", "第四名");
map.put(null, null);
map.put(null, null); //两个null只会输出一个
Set set = map.keySet(); //Set需要导包
Iterator it = set.iterator(); //Iterator需要导包
while (it.hasNext()) {
Object obj = it.next();
Object object = map.get(obj);
System.out.println("key:" + obj + " value:" + object);
}
}
}
参考源码:
package my.map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
Map<String,String> map=new HashMap<String, String>();
//使用put添加元素
map.put("first","张三");
map.put("second","李四");
map.put("third","王五");
map.put("fourth","赵六");
map.put("fifth","李明");
//存放两个key-value为空的元素,打印时出现一个
map.put(null, null);
map.put(null, null);
//方式1.使用 keySet
Set set = map.keySet();// map中的键其实就是一个set集合
Iterator it = set.iterator();
while (it.hasNext()) {
Object str = it.next();// 键
Object object = map.get(str);// 值
System.out.println("键 : "+str + " 值:" + object);
}
//方式2:使用entrySet
Set set1 = map.entrySet();
Iterator it1 = set.iterator();
while (it.hasNext()) {
Entry entry = (Entry) it.next();// 键+值
Object key = entry.getKey();
Object value = entry.getValue();// 真正的值
System.out.println(key + "--->" + value);
}
}
}