集合技术点总结

一:Collection接口

1.概述

英文名称Collection,是用来存放对象的数据结构。其中长度可变,而且集合中可以存放不同类型的对象。并提供了一组操作成批对象的方法。

数组的缺点:长度是固定不可变的,访问方式单一,插入、删除等操作繁琐。

2.集合的继承结构

Collection接口

-- List接口  : 数据有序,可以重复。

   -- ArrayList子类

   -- LinkedList子类

-- Set接口  : 数据无序,不可以存重复值

   -- HashSet子类

-- Map接口  : 键值对存数据

-- HashMap

Collections工具类

测试集合的常用方法

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Test_301_Collection {
       public static void main(String[] args) {
              Collection c = new ArrayList();//接口无法直接创建对象
              c.add("hello");//添加元素
              c.add("java");//添加元素
              c.add("~");//添加元素
              c.add(10);//jdk5后有自动装箱功能,相当于把10包装Integer.valueOf(10)
              System.out.println(c.remove("~"));//移除元素
              System.out.println(c.contains("a"));//判断包含关系
              System.out.println(c.size());//集合的长度
              System.out.println(c);            
              //for遍历集合
              for(int i =0 ;i<c.size();i++) {
                     System.out.println(c.toArray()[i]);
              }
              //iterator迭代器遍历
              Iterator it = c.iterator();//对 collection 进行迭代的迭代器

              while (it.hasNext()) {//如果仍有元素,则返回 true
                     System.out.println(it.next());//返回迭代获取到的下一个元素
              }   } }

3.list接口

概述:有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

3.1 特点

1 数据有序

2 允许存放重复元素

3 元素都有索引

3.2 常用方法

ListIterator<E> listIterator()

          返回此列表元素的列表迭代器(按适当顺序)。

 ListIterator<E> listIterator(int index)

          返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。

 void add(int index, E element)

          在列表的指定位置插入指定元素(可选操作)。

 boolean addAll(int index, Collection<? extends E> c)

          将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。

 List<E> subList(int fromIndex, int toIndex)

     返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。

E get(int index)

          返回列表中指定位置的元素。  

int indexOf(Object o)

          返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。

测试常用方法

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator; 
//这类用来测试List接口的常用方法
public class Test1_List {
    public static void main(String[] args) {
       //1、创建List对象
       //特点1:List集合元素都有索引,可以根据索引直接定位元素
       List list = new ArrayList();      
       //2、常用方法
       list.add(111);
       list.add(222);
       list.add(333);
       list.add(444);
       list.add('a');
       list.add("abc");   
       list.add(3,666);//在3的索引处添加指定元素
       //特点2:元素有序, 怎么存就怎么放
       System.out.println(list);//[111, 222, 333, 666, 444, a, abc]      
       Object obj = list.get(4);//get(m)-m是索引值,获取指定索引位置的元素
       System.out.println(obj);          
       //3、迭代/遍历集合中的元素
       //使用Collection接口提供的iterator()
       Iterator it = list.iterator();
       while(it.hasNext()) {//判断集合里有没有下个元素
           Object o = it.next();
//         System.out.println(o);
       }     
       //使用List接口提供的listIterator()
       //interfaceListIterator extends Iterator
       //区别:可以使用父接口的功能,同时拥有自己的特有功能,不仅顺序向后迭代还可以逆向迭代
       ListIterator it2 = list.listIterator();
       while(it2.hasNext()) {
           Object o = it2.next();
//         System.out.println(o);
       }      
       System.out.println();    
       List list2 = list.subList(1, 3);//subList(m,n)-m是开始索引,n是结束索引,其中含头不含尾类似于String.subString(m,n)
       System.out.println(list2);      
    }   
}

3.3 ArrayList

1)     存在于java.util包中。

2)     内部用数组存放数据,封装了数组的操作,每个对象都有下标。

3)     内部数组默认初始容量是10。如果不够会以1.5倍容量增长。

4)     查询快,增删数据效率会降低。

3.4 常用方法测试

import java.util.ArrayList;
public class Test3_AL {
       public static void main(String[] args) {
              ArrayList list = new ArrayList();
              list.add("aaa");//存入数据
              list.add("123");
              list.add("ccc");
              list.add("ddd");
              System.out.println(list);//list中内容
              System.out.println(list.size());//集合长度
              System.out.println(list.get(1));//根据下标获取元                    
              System.out.println();
              System.out.println(list.remove(2));//移除下标对应的元素
              System.out.println(list);                   
                     //下标遍历
                     for (int i = 0; i < list.size(); i++) {
                            System.out.print(list.get(i));
                     }
       //Iterator迭代遍历,封装了下标
                     Iterator<String> it = list.iterator();

                     while (it.hasNext()) {//如果有数据
                            String s = it.next();//一个一个向后遍历
                            System.out.println(s);
                     }     
              }
}

3.5 LinkedList

概述:双向链表,两端效率高。底层就是数组和链表实现的。

3.6 常用方法

add()
get()
size()
remove(i)
remove(数据)
iterator()
addFirst()  addLast()
getFirst()  getLast()
removeFirst()  removeLast()

简单测试

双向链表:下标遍历效率低,迭代器遍历效率高
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList; 
public class tt {
       public static void main(String[] args) throws Exception {
              LinkedList ll = new LinkedList ();
              for (int i = 0; i < 100000; i++) {
                    ll.add(100);
              }
              f1(ll);
              f2(ll);
       } 
       private static void f2(LinkedList<Integer> ll) {
              long t = System.currentTimeMillis();
              Iterator it = ll.iterator();
              while(it.hasNext()) {
                     it.next();
              }
              t = System.currentTimeMillis()-t;
              System.out.println("=====iterator========="+t);//16
       }
       private static void f1(LinkedList<Integer> ll) {
              long t = System.currentTimeMillis();
              for (int i = 0; i < ll.size(); i++) {
                     ll.get(i);
              }
              long t1 = System.currentTimeMillis();
              System.out.println("~~~~for~~~~~~~"+(t1-t));//9078
       }
}

3.7扩展

ArrayList扩展

ArrayList相当于在没指定initialCapacity时就是会使用延迟分配对象数组空间,当第一次插入元素时才分配10(默认)个对象空间。假如有20个数据需要添加,那么会分别在第一次的时候,将ArrayList的容量变为10 (如下图一);之后扩容会按照1.5倍增长。也就是当添加第11个数据的时候,Arraylist继续扩容变为10*1.5=15(如下图二);当添加第16个数据时,继续扩容变为15 * 1.5 =22个

ArrayList没有对外暴露其容量个数,查看源码我们可以知道,实际其值存放在elementData对象数组中,那我们只需拿到这个数组的长度,观察其值变化了几次就知道其扩容了多少次。怎么获取呢?只能用反射技术了。

3.8链表和数组的区别

List是一个接口,它有两个常用的子类,ArrayList和LinkedList,看名字就可以看得出一种是基于数组实现另一个是基于链表实现的。

数组ArrayList遍历快,因为存储空间连续;链表LinkedList遍历慢,因为存储空间不连续,要去通过指针定位下一个元素,所以链表遍历慢。

数组插入元素和删除元素需要重新申请内存,然后将拼接结果保存进去,成本很高。例如有100个值,中间插入一个元素,需要数组重新拷贝。而这个动作对链表来说,太轻松了,改变一下相邻两个元素的指针即可。所以链表的插入和修改元素时性能非常高。

实际开发就根据它们各自不同的特点来匹配对应业务的特点。业务一次赋值,不会改变,顺序遍历,就采用数组;业务频繁变化,有新增,有删除,则链表更加适合。

4Set接口

概述:

一个不包含重复元素的 collection。

数据无序(因为set集合没有下标)。

由于集合中的元素不可以重复。常用于给数据去重。

特点:

HashSet:底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K,存入内部的HashMap中。当然K仍然不许重复。

TreeSet:底层就是TreeMap,也是红黑树的形式,便于查找数据。

HashMap实现中,当哈希值相同的对象,会在同一个hash值的位置存储不同属性的数据。

4.1常用方法:

boolean add(E e):添加元素。
boolean addAll(Collection  c):把小集合添加到大集合中 。
boolean contains(Object o) : 如果此 collection 包含指定的元素,则返回 true。
boolean isEmpty() :如果此 collection 没有元素,则返回 true。
Iterator<E> iterator():返回在此 collection 的元素上进行迭代的迭代器。
boolean remove(Object o) :从此 collection 中移除指定元素的单个实例。
int size() :返回此 collection 中的元素数。
Objec[] toArray():返回对象数组

常用方法测试:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; 
public class Test0_Map {
       public static void main(String[] args) {
              Set set = new HashSet ();
              set.add("hello");
              set.add("b");
              set.add("a");
              set.add("world");
              set.add("b");
              //不存重复元素,元素无序
              System.out.println(set);            
              //迭代器
              Iterator it = set.iterator();
              while(it.hasNext()) {
                     System.out.println(it.next());
              }
       }
}

4.2hashSet

概述:此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

获取hashset里的数据:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test0_Map {
    public static void main(String[] args) {
       HashSet set = new HashSet();
       set.add("a");
       set.add("e");
       set.add("b");
       set.add("a");
       set.add("b");      
       System.out.println(set);//无序,不重复      
       Iterator it = set.iterator();
       while(it.hasNext()) {
           System.out.println(it.next());
       }      
    }
}

二:Map接口

概述;

java.util接口 Map<K,V>

类型参数: K - 此映射所维护的键的类型V - 映射值的类型。

也叫哈希表、散列表。常用于存 键值对 结构的数据。其中的键不能重复,值可以重复.

1.1特点:

Ø  可以根据键 提取对应的值

Ø  键不允许重复,如果重复值会被覆盖

Ø  存放的都是无序数据

Ø  初始容量是16,默认的加载因子是0.75

1.2 继承结构

1.3常用方法:

void clear()          从此映射中移除所有映射关系(可选操作)。
boolean containsKey(Object key)          如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(Object value)          如果此映射将一个或多个键映射到指定值,则返回 true。
V get(Object key)          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
boolean isEmpty()          如果此映射未包含键-值映射关系,则返回 true。
V put(K key, V value)          将指定的值与此映射中的指定键关联(可选操作)。
void putAll(Map<? extends K,? extends V> m)          从指定映射中将所有映射关系复制到此映射中(可选操作)。
V remove(Object key)          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
int size()          返回此映射中的键-值映射关系数。
Set<Map.Entry<K,V>> entrySet()          返回此映射所包含的映射关系的 Set 视图。

测试:

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
  
public class Test0_Map {
       public static void main(String[] args) {
              Map map = new HashMap ();
              map.put("001", "钢铁侠");
              map.put("002", "蜘蛛侠");
              map.put("003", "绿巨人");
              map.put("004", "灭霸");
              map.put("005", "美国队长");
              map.put("005", "凤姐");
              System.out.println(map.containsKey("001"));
              System.out.println(map.containsValue("美国队长"));
              System.out.println(map.isEmpty());
              System.out.println(map.get("003"));
              System.out.println(map.remove("001"));
              System.out.println(map.size());
              Map map2 = new HashMap ();
              map2.put("999", "刘德华");
map.put(null,null);//可以存入键为null,值也null的数据 
              map.putAll(map2);
              System.out.println(map);             
              //keySet()返回键的set集合,把map的key形成set集合
              Set set = map.keySet();
              System.out.println(set);                          
              //map集合的遍历,
              //方式1:keySet():把map中的可以放入set集合
              //遍历方式1:keySet ()
Set set = m.keySet();
              Iterator it = set.iterator();
              while(it.hasNext()) {
                     String key = (String) it.next();
                     String val = (String) m.get(key);
                     System.out.println(key+"="+val);
              }      
              //遍历方式2:entrySet ()
Set set2 = m.entrySet();
              Iterator it2 = set2.iterator();
              while(it2.hasNext()) {
                     Entry en = (Entry) it2.next();
                     String key = (String) en.getKey();
                     String value = (String) en.getValue();
                     System.out.println(key+"=="+value);
              }             
       }
}

1.4 hashmap

HashMap的键要同时重写hashCode()和equals()

hashCode()用来判断确定hash值是否相同

equals()用来判断属性的值是否相同

-- equals()判断数据如果相等,hashCode()必须相同

-- equals()判断数据如果不等,hashCode()尽量不同

概述:

基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。

HashMap底层是一个Entry数组,当存放数据时会根据hash算法计算数据的存放位置。算法:hash(key)%n,n就是数组的长度。

当计算的位置没有数据时,就直接存放,当计算的位置有数据时也就是发生hash冲突的时候/hash碰撞时,采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。

读取hashmap中的数据:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; 
public class Test0_Map {
       public static void main(String[] args) {
              HashMap map = new HashMap ();
              map.put(100, "刘德华");
              map.put(101, "梁朝伟");
              map.put(102, "古天乐");
              map.put(103, "周润发"); 
              //遍历方式1:keySet ()
              Set set = m.keySet();
              Iterator it = set.iterator();
              while(it.hasNext()) {
                     String key = (String) it.next();
                     String val = (String) m.get(key);
                     System.out.println(key+"="+val);
              }     
              //遍历方式2:entrySet ()
              Set set2 = m.entrySet();
              Iterator it2 = set2.iterator();
              while(it2.hasNext()) {
                     Entry en = (Entry) it2.next();
                     String key = (String) en.getKey();
                     String value = (String) en.getValue();
                     System.out.println(key+"=="+value);
              }
       }
}
接收用户输入的一串字符串,统计出现的每个字符的个数
import java.util.HashMap;
import java.util.Scanner;
public class Test2_Count {
       public static void main(String[] args) {
              //abacbcda
              String s = new Scanner(System.in).nextLine();             
              //a 1  b 2  c 1
              HashMap<Character,Integer> map = new HashMap<>();
              //遍历字符串获取每个字符
              for(int i = 0;i<s.length();i++) {
                     //1,取出字符串中的每个字符
                     char c = s.charAt(i);                    
                     //拿着字符查个数
                     Integer count = map.get(c);
                     //如果取出来是null,就存1,
                     if(count==null) {
                            map.put(c, 1);
                     }else {
                            //如果取出来有值,计数加1
                            map.put(c,count+1);
                     }
              }
              System.out.println(map);
       }
}

1.5 Collection工具类

常用方法:

Collections.sort(List<> list):根据元素的自然顺序 对指定列表按升序进行排序。
Collections.max():根据元素的自然顺序,返回给定 collection 的最大元素。
Collections.min():根据元素的自然顺序 返回给定 collection 的最小元素。
Collections.swap(List,i,j):在指定列表的指定位置处交换元素。
Collections.addAll():

测试:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Test4_Collections {
       public static void main(String[] args) {
              List<String> list = new ArrayList();             
              //添加多个元素
              Collections.addAll(list,
                            "3","30","23","15","29","12","26");             
              //元素排序
              Collections.sort(list);
          //默认是字符顺序:[12,15,23,26,29, 3, 30]
              System.out.println(list);            
              //自己定义比较方式
              Collections.sort(list, new Comparator<String>() {
                     //自定义比较器,sort()自动调用
                     @Override
                     public int compare(String o1, String o2) {
                            //把字符串转成int比大小
                            int a = Integer.parseInt(o1);
                            int b = Integer.parseInt(o2);
                            //o1大是正数,o1小是负数,相等是0
                            return a-b;
                     }
              });
              System.out.println(list);
       }
}

hashmap扩展

成长因子:

static final float DEFAULT_LOAD_FACTOR = 0.75f;

前面的讲述已经发现,当你空间只有仅仅为10的时候是很容易造成2个对象的hashcode 所对应的地址是一个位置的情况。这样就造成 2个 对象会形成散列桶(链表)。这时就有一个加载因子的参数,值默认为0.75 ,如果你hashmap的 空间有 100那么当你插入了75个元素的时候 hashmap就需要扩容了,不然的话会形成很长的散列桶结构,对于查询和插入都会增加时间,因为它要一个一个的equals比较。但又不能让加载因子很小,如0.01,这样显然是不合适的,频繁扩容会大大消耗你的内存。这时就存在着一个平衡,jdk中默认是0.75,当然负载因子可以根据自己的实际情况进行调整。

猜你喜欢

转载自blog.csdn.net/KAITUOZHEMJ/article/details/112699508
今日推荐