Java 中提供的一种容器,长度可变,存储的是对象。
类集是 Java 数据结构的实现
链表
链表是离散存储线性结构 n 个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一个后续节点,首节点没有前驱节点,尾节点没有后续节点。
- 优点:空间没有限制,插入删除很快
- 缺点,存储数据很慢
class Node{Object data;Node next;}
二叉树
class Node{Object data;Node left, right;}
红黑树
栈
先进后出
队列
先进先出
Collection 接口
在整个 Java 类集中保存单值的最大操作父接口
常用子接口 List(允许重复), Set(不允许重复)
List 接口
public interface List extends Collection 子接口的定义
实现类
ArrayList(动态数组),
ArrayList<String> data = new ArrayList<>();data.add("Hello ");//返回 truedata.add(1, "cnmcnm"); //List 接口单独定义的data.add("World");data.remove(1);//根据索引删除内容data.remove("World");//删除指定对象System.out.println(data);//长度是任意长for(int i=0; i<data.size(); i++){System.out.print(data.get(i)+", ");}
LinkedList(链表)
双向链表实现,增加删除更快,查找慢(与 ArrayList 相反)
vector
同步的
public static void main(String[] args) {//Vector:Vector<String> data = new Vector<>();data.add("Hello ");//返回 truedata.add(1, "cnmcnm"); //List 接口单独定义的data.add("World");data.remove(1);//根据索引删除内容data.remove("World");//删除指定对象System.out.println(data);//长度是任意长for(int i=0; i<data.size(); i++){System.out.print(data.get(i)+", ");}}
ListIterator 和 Iterator
Iterator 属于迭代输出,基本的操作原理:是不断的判断是否有下一个元素,有的话,则直接输出。
public static void main(String[] args) {//由前向后的单向输出ArrayList<Integer> data = new ArrayList<>();data.add(1);data.add(2);data.add(3);data.add(4);data.add(5);Iterator<Integer> iterator = data.iterator();while(iterator.hasNext()){//判断下一个数据是否有//在迭代的时候不能进行集合中的remove方法,要用迭代器的remove方法System.out.print(iterator.next()+", ");//取出数据}iterator.remove();//删除指针所指的当前内容System.out.println("\n"+data.size());}
public static void main(String[] args) {//由前向后的单向输出ArrayList<Integer> data = new ArrayList<>();data.add(1);data.add(2);data.add(3);data.add(4);data.add(5);ListIterator<Integer> iterator = data.listIterator();iterator.add(100);//该元素紧接在next()返回的元素之前插入iterator.next();iterator.next();iterator.set( 20000);iterator.previous();iterator.previous();iterator.previous();while(iterator.hasNext()){System.out.println(iterator.next());}}
增强 for
用于迭代数组 或 集合(Collection下的集合)
set 集合
不包含重复元素的集合。
- 注意:如果将可变对象用作set元素,则必须非常小心
HashSet
散列存放(哈希表在后续HashMap详细讲)
不保证存储顺序
public static void main(String[] args) {HashSet<String> set = new HashSet<>();set.add("一二三四五");set.add("上山打老虎");set.add("老虎没打到");set.add("打到小松鼠");set.add("打到小松鼠");for (String s : set) {System.out.println(s);}/*上山打老虎打到小松鼠一二三四五老虎没打到*/}
TreeSet 和 Comparable
二叉树存储 有序,基于 Map 集合
- 此类的
iterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时间修改集合,除了通过迭代器自己的remove方法之外,迭代器将抛出ConcurrentModificationException。
一定要实现 comparable 接口才可以实现比较
public static void main(String[] args) {TreeSet<String> data = new TreeSet<>();data.add("A");data.add("C");data.add("D");data.add("B");TreeSet<Person> data2 = new TreeSet<>();Person p1 = new Person("张三", 14);Person p2 = new Person("张三", 15);data2.add(p1);data2.add(p2);for (Person s:data2) {System.out.println(s);}}static class Person implements Comparable<Person>{private String name;private int age;@Overridepublic int compareTo(Person o) {//自己定义规则//返回的数据 负数(this小)/0(相等)/正数(this大)if(this.age>o.age){return 1;}else if(this.age == o.age){return 0;}return -1;}
重复元素的说明
Map 集合(Mapping 映射)
多值存储,存储的是 键值对 数据(钥匙和锁)
键不可以重复,每一个键映射一个值keySet();取出键 再迭代put 添加数据getremove(); 取出并删除
哈希表
Hashmap
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,//先得到hash值,即存储位置boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)//判断哈希表是否为空n = (tab = resize()).length; //扩容if ((p = tab[i = (n - 1) & hash]) == null) //取余运算 判断是否在桶中有数据tab[i] = newNode(hash, key, value, null); //创建一个新节点else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))//判断键是否存在e = p; //覆盖老的值else if (p instanceof TreeNode) //是否是树节点8个及以上e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else { //遍历链表for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash); // 变成二叉树break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for key 覆盖操作V oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;//修改次数if (++size > threshold)resize(); //看是否到达默认加载因子,是则扩容afterNodeInsertion(evict);return null;}
//HashMap/HashTable/ConCurrentMap//TreeMap//LinkedHashMappublic static void main(String[] args) {HashMap<String, String> m1 = new HashMap<>();m1.put("key1", "我 草泥马");//将指定的值与此映射中的指定键相关联。// 如果映射先前包含键的映射,则替换旧值m1.put("key2", "我 是你爹");Set<String> set = m1.keySet();//返回此映射中包含的 键 的Set视图for(String key: set){System.out.println(key+"+"+m1.get(key));//get()// 返回指定键映射到的值,如果此映射不包含键的映射,则返回null}Collection<String> values = m1.values();//返回此映射中包含的值的Collection视图。for(String value: values){System.out.println(value);}m1.remove("key1");//从此映射中删除指定键的映射(如果存在)。System.out.println(m1);}
HashMap/ 线程不安全 效率高
HashTable/线程安全(排队执行,效率低)
ConCurrentMap 采用分段锁(多个排队的队伍)机制,保证线程安全,效率又比较高
散列因子
给到0.9,可能有的桶中的链表已经很长了,所以效率更低。
故散列因子越高,查询效率越低。
思考好初始容量,减少散列次数(重建数据结构)。
JDK9 新特性
public static void main(String[] args) {List<String> list = List.of("cxcx,xcxc,");//不可以改变//list.add("12345");//报错,因为不可以添加Set<String> set = Set.of("cxcx,xcxc,");//不可以改变for(String s:set){System.out.println(s);}Map<String, String> map = Map.of("haha1", "一二三四五", "haha2", "上山打老虎");Set<String> keyset = map.keySet();for(String key:keyset){System.out.println(key+" -> "+map.get(key));}}
