Java集合学习

集合

1.Collection接口

  1. 集合主要是两组(单列集合 , 双列集合)

  2. Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合

  3. Map 接口的实现子类 是双列集合,存放的 K-V

collection接口的特点

  1. colletion实现子类可以存放多个元素,每个元素可以是Object

  2. 有些Collection的实现类,可以存放重复的元素,有些不可以

  3. 有些Collection的实现类,有些是有序的(List),有些不是有序(Set)

  4. Collection接口没有直接的实现子类,是通过它的子接口Set 和 List 来实现的

List list = new ArrayList();
// add:添加单个元素
list.add("jack");
list.add(10);//list.add(new Integer(10))
list.add(true);
System.out.println("list=" + list);
// remove:删除指定元素
list.remove(0);//删除第一个元素
list.remove(true);//指定删除某个元素
System.out.println("list=" + list);
System.out.println(list.contains("jack"));//T   // contains:查找元素是否存在
System.out.println(list.size());//2 // size:获取元素个数
System.out.println(list.isEmpty());//F // isEmpty:判断是否为空
list.clear();// clear:清空
System.out.println("list=" + list);
// addAll:添加多个元素
ArrayList list2 = new ArrayList();
list2.add("红楼梦");
list2.add("三国演义");
list.addAll(list2);
System.out.println("list=" + list);
// containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));//T
list.add("聊斋"); 
list.removeAll(list2);  // removeAll:删除多个元素 
使用迭代器遍历
  1. lterator对象称为迭代器,主要用于遍历 Collection 集合中的元素。

  2. 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。

  3. lterator 仅用于遍历集合,Iterator 本身并不存放对象

Collection col = new ArrayList();
col.add(new Book("三国演义", "罗贯中", 10.1));
col.add(new Book("小李飞刀", "古龙", 5.1));
col.add(new Book("红楼梦", "曹雪芹", 34.6));
//1. 先得到 col 对应的迭代器
Iterator iterator= col.iterator();
//使用while循环来遍历
while(iterator.hasNext()){
    //返回下一个元素,类型是 Obj
    Object next = iterator.next();
    System.out.println(next.toString());
}
使用增强for遍历
for (Object book:col) {
    System.out.println(book.toString());
}

2.List 接口

List接口是 Collection 接口的子接口

  • List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复

  • List集合中的每个元素都有其对应的顺序索引,即支持索引

List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

常用api

/**
 * Object get(int index)//获取指定 index 位置的元素
 * int indexOf(Object obj):返回 obj 在集合中首次出现的位置
 * int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
 * Object remove(int index):移除指定 index 位置的元素,并返回此元素
 * Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当替换
 * List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
 *
 */
List 的三种遍历方式
List list = new ArrayList();
    list.add(new Book("三国演义", "罗贯中", 10.1));
    list.add(new Book("小李飞刀", "古龙", 5.1));
    list.add(new Book("红楼梦", "曹雪芹", 34.6));
//1. 迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    Object obj = iterator.next();
    System.out.println(obj);
}
System.out.println("=====增强 for=====");
//2. 增强 for
for (Object o : list) {
    System.out.println("o=" + o);
}
System.out.println("=====普通 for====");
//3. 使用普通 for
for (int i = 0; i < list.size(); i++) {
    System.out.println("对象=" + list.get(i));
}
ArrayList

ArrayList 的注意事项

  • permits all elements, including null,ArrayList 可以加入null,并且多个

  • ArrayList 是由数组来实现数据存储的[后面老师解读源码]

  • ArrayList 基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码.在多线程情况下,不建议使用ArrayList

ArrayList的底层操作机制源码分析)

  • ArrayList中维护了一个Object类型的数组elementData.

transient Objectll elementData;//transient 表示瞬间,短暂的,表示该属性不会被序列号
  • 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,

    如需要再次扩容,则扩容elementData为1.5倍。

  • 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。

Vector集合
  1. Vector底层也是一个对象数组,protected Object[] elementData;

  2. Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized

public synchronized void copyInto(Object[] anArray) {
    System.arraycopy(elementData, 0, anArray, 0, elementCount);
}
Vector和ArrayList比较
ArrayList可变数组jdk1.2线程不安全,效率高如果有参构造1.5倍,如果是无参第一次10,从第二次开始安1.5扩
Vector可变数组jdk1.0安全,效率不高如果是无参,默认10,满后,就按2倍扩容,如果指定大小,则每次直接按2倍扩容.
LinkedList

LinkedList的全面说明

  • LinkedList底层实现了双向链表和双端队列特点

  • 可以添加任意元素(元素可以重复),包括null

  • 线程不安全,没有实现同步

LinkedList的底层操作机制

  • LinkedList底层维护了一个双向链表.

  • LinkedList中维护了两个属性first和last分别指向 首节点和尾节点

  • 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.

  • 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。

ArrayList 和 LinkedList 的比较
底层结构增删的效率改查的效率
Arra可变数组较低数组扩容较高
LinkedList双向链表较高,通过链表追加较低

如何选择

  • 如果我们改查的操作多,选择ArrayList

  • 如果我们增删的操作多,选择LinkedList

  • 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList,但是,在一个项目中,根据业务灵活选择,

3.Set 接口

特点:

  • 无序,没有索引。

  • 不允许重复元素,所以最多包含一个null。

  • 和 List 接口一样, Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样

遍历方式
Set set = new HashSet();
set.add("john");
set.add("lucy");
set.add("john");//重复
set.add("jack");
set.add("hsp");
Iterator iterator=set.iterator();
//迭代器遍历
while (iterator.hasNext()){
    Object obj=iterator.next();
    System.out.println(obj);
}
//增强for
for (Object objs:set) {
    System.out.println(objs);
}
HashSet
  • HashSet实现了Set接口

  • HashSet实际上是HashMap.

    public HashSet() { 
        map = new HashMap<>(); 
    }
  • 可以存放null值,但是只能有一个null

  • HashSet不保证元素是有序的,取决于hash后,再确定索引的结果.(即,不保证存放元素的顺序 和取出顺序一致)

  • 不能有重复元素/对象.在前面Set接口使用已经讲过

HashSet 的底层逻辑
  1. HashSet 底层是HashMap

  2. 添加一个元素时,先得到hash值-会转成->索引值

  3. 找到存储数据表table,看这个索引位置是否已经存放的有元素

  4. 如果没有,直接加入

  5. 如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加到最后

  6. 在Java8中,如果一条链表的元素个数到达TREEIFYTHRESHOLD(默认是8),并且table的大小>=MIN TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

LinkedHashSet
  • LinkedHashSet 是 HashSet 的子类

  • LinkedHashSet 底层是一个 LinkedHashMap,底层维护了一个 数组+双向链表

  • LinkedHashSet 根据元素的hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

  • LinkedHashSet不允许添重复元素

4.Map 接口

Map 接口实现类的特点
  1. Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value

  2. Map 中的key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node对象中

  3. Map 中的 key 不允许重复

  4. Map中的value 可以重复

  5. Map 的key 可以为 null,value 也可以为null,注意 key 为null,只能有一个,value 为null,可以多个.

  6. 常用String类作为Map的key

  7. key 和 value 之间存在单向一对一关系,即通过指定的key 总能找到对应的 value

Map相关的Api
Map map = new HashMap();
map.put("李四", new Book("三国演义", "罗贯中", 10.1));
map.put("张三","100");
map.put("李四","120");//此处会替换
System.out.println(map.get("李四"));
// remove:根据键删除映射关系
map.remove(null);
System.out.println("map=" + map);
// get:根据键获取值
Object val = map.get("鹿晗");
System.out.println("val=" + val);
// size:获取元素个数
System.out.println("k-v=" + map.size());
// isEmpty:判断个数是否为 0
System.out.println(map.isEmpty());//F
// clear:清除 k-v
map.clear();
System.out.println("map=" + map);
// containsKey:查找键是否存在
System.out.println("结果=" + map.containsKey("hsp"));//T
Map 接口遍历方法
方式一:

先取出所有的key,然后再获得value值

Map map = new HashMap();
    map.put("张三","100");
    map.put("李四","120");
//第一组: 先取出 所有的 Key , 通过 Key 取出对应
Set keys=map.keySet();
//第一种遍历方式,增强for
for (Object key:keys) {
    System.out.println("key="+key+":"+"value="+map.get(key));
}
System.out.println("----第二种方式迭代器--------");
Iterator iterator = keys.iterator();
 while (iterator.hasNext()) {
   Object key = iterator.next();
       System.out.println(key + "-" + map.get(key));
 }
方式二:

把所有的 values 取出来

Collection collections=map.values();
//foreach
for (Object value:collections) {
    System.out.println(value);
}
//迭代器
Iterator iterator=collections.iterator();
while (iterator.hasNext()){
    Object objs=iterator.next();
    System.out.println(objs);
}
方式三:

通过 EntrySet 来获取 k-v

Set entrySet = map.entrySet();// EntrySet<Map.Entry<K,V>>
//(1) 增强 for
for (Object entry : entrySet) {
//将 entry 转成 Map.Entry
    Map.Entry m = (Map.Entry) entry;
    System.out.println(m.getKey() + "-" + m.getValue());
}
//(2) 迭代器
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
    Object entry = iterator.next();
    //System.out.println(next.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)
    //向下转型 Map.Entry
    Map.Entry m = (Map.Entry) entry;
    System.out.println(m.getKey() + "-" + m.getValue());
}
HashMap总结
  • Map接口的常用实现类:HashMap、Hashtable和Properties。

  • HashMap是 Map接口使用频率最高的实现类。

  • HashMap 是以key-val 对的方式来存储数据(HashMapSNode类型)

  • key 不能重复,但是值可以重复,允许使用null键和null值。

  • 如果添加相同的key,则会覆盖原来的key-val,等同于修改.(key不会替换,val会替换)6)与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.(jdk8的hashMap 底层 数组+链表+红黑树)

  • HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

Hashtable
  • 存放的元素是键值对:即K-V

  • hashtable的键和值都不能为null,否则会抛出NuPointerException

  • hashTable 使用方法基本上和HashMap一样

  • hashTable 是线程安全的(synchronized),hashMap 是线程不安全的

Properties
  • Properties类继承自Hashtable类并且实现了Map接口,也是使用一种健值对的形式来保存数据。

  • Properties 还可以用于从xcxc.properties 文件中,加载数据到Properties类对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值