数组集合应用java
// ArraysList 增删慢 查询快 // 根据源码 无参构造方法建立出来的是长度为0的数组{} List<Integer> list = new ArrayList<>(); // 此时add方法进行源码扩容 list.add(100); System.out.println(list.get(0));
public boolean add(E e) { // 不须要关注 modCount++; // e对象 elementData集合数组元素 size当前数组长度 add(e, elementData, size); // 无论成功失败 均返回true return true; } private void add(E e, Object[] elementData, int s) { // 知足条件 进入扩容算法 否则就进行正常赋值操做 if (s == elementData.length) elementData = grow(); elementData[s] = e; size = s + 1; } private Object[] grow() { // 至少须要加一个长度 return grow(size + 1); } private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); } private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; // 新长度加上旧长度的0.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity <= 0) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // DEFAULT_CAPACITY 默认长度10 return Math.max(DEFAULT_CAPACITY, minCapacity); // 超出最大二进制,符号会改变,会变为负数 if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
// LinkedList: 使用双向链表结构,增删快,查找慢 // (这种结构和ArrayList的数组结构正好是互补状态) LinkedList<Integer> ll = new LinkedList<>(); // 模拟栈结构 // 压栈 ll.push(100); ll.push(200); // 弹栈 Integer i = ll.pop(); // 200 System.out.println(i); // 1 System.out.println(ll.size()); // 下面注释参考 不建议使用 // 添加集合中第一个元素 // ll.addFirst(100); // ll.addFirst(200); // 移除集合中第一个元素 // Integer removeData = ll.removeFirst(); // 200 // System.out.println(removeData); // 1 // System.out.println(ll.size());
用法和ArrayList基本一致,是线程安全的。面试
// 10 初始化长度 20 扩容增量 此处是相较于ArrayList不一样之处 List<Integer> v = new Vector<>(10, 20); v.add(100); v.add(200);
// Iterator 迭代器 做用遍历集合 // Iterator迭代Collection下List和Set ListIterator迭代List下面的集合 List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); Iterator<Integer> iterator = list.iterator(); iterator.next(); // 必需要有值才能移除即前面调用next()方法,固然没值也会报错 iterator.remove();; // 4 System.out.println(list.size()); // 判断迭代器下个是否有值 while(iterator.hasNext()) { // 迭代器往下走,并取值 Integer i = iterator.next(); // 输出 2 3 4 5 System.out.println(i); } // 用法和iterator差很少 ListIterator<Integer> listIterator = list.listIterator(); // 获取向上走的值 listIterator.hasPrevious(); // 添加 listIterator.add(10); // 设置 listIterator.next(); listIterator.set(200); listIterator.previous(); // 5 System.out.println(list.size()); while(listIterator.hasNext()) { // 输出 200 3 4 5 System.out.println(listIterator.next()); }
Set集合是没有重复的元素,包括null只会存在一个算法
// HashSet是散列存放的数据结构(哈希表) // 本质是 map = new HashMap<>() // 因为已经存在双值存储的哈希表 因此这边重复利用了造成如今的单值存储的哈希表 Set<String> set = new HashSet<>(); // map.put(e, PRESENT) set.add("人有悲欢离合"); set.add("月有阴晴圆缺"); set.add("希望人长久"); set.add("希望人长久"); set.add("千里共婵娟"); set.add("千里共婵娟"); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); }
public static void main(String[] args) { // TreeSet 使用二叉树进行存储的 有序(天然顺序) Set<Person> set = new TreeSet<>(); Person p1 = new Person("张三", 13); Person p2 = new Person("李四", 14); Person p3 = new Person("麻五", 14); set.add(p1); set.add(p2); set.add(p3); // 遍历前需制定本身的排序规则, 不然可能报错 // Person{name='张三', age=13} // Person{name='李四', age=14} // 比较规则相同的值,不被储存 for (Person p : set) { System.out.println(p); } // set.add("C"); // set.add("B"); // set.add("A"); // set.add("D"); // A B C D // Iterator<String> iterator = set.iterator(); // while(iterator.hasNext()) { // System.out.println(iterator.next()); // } } static class Person implements Comparable<Person> { private String name; private int age; @Override public int compareTo(Person o) { // this与0比较 // 返回this小/0/大 if (this.age > o.age) { return 1; } else if (this.age == o.age) { return 0; } return -1; } public Person(String name, int age) { 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; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
Map(Mapping 映射)集合存储的是 键值对 数据,Map的键不可重复。
影响HashMap的实例化性能的是初始容量和负载因子。
HashMap/Hashtable/ConcurrentHashMap TreeMap/LinkedHashMap使用方法基本一致。数组
HashMap是线程不安全,效率高。HashTable线程安全, 效率低。
ConcurrentHashMap采用分段锁机制,保证线程安全,效率较高。安全
TreeMap是有序的排。
LinkedHashMap存储有序。数据结构
Map<String, String> map = new HashMap<>(); // 存值 map.put("k1", "v1"); // 取值 v1 System.out.println(map.get("k1")); map.put("k2", "v2"); // 遍历 Set<String> set = map.keySet(); for (String key : set) { // k1->v1 // k2->v2 System.out.println(key + "->" + map.get(key)); } // 转为Collection集合 Collection<String> c = map.values(); for (String s : c) { System.out.println(s); }
// 构造方法 public HashMap() { // 默认加载因子0.75f this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } public V put(K key, V value) { // 先计算键的hash值,而后调用putVal return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { // n是桶(数组)的长度 Node<K,V>[] tab; Node<K,V> p; int n, i; // table是默认的16个长度的数组赋值给tab if ((tab = table) == null || (n = tab.length) == 0) // resize扩容算法 n扩容以后的长度 n = (tab = resize()).length; // (n - 1) & hash 是取余后的长度 数组下标没有值直接赋值 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; // key存在新值覆盖老值 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; // 判断是树节点 按红黑树套路进行存储 else if (p instanceof TreeNode) 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 1st treeifyBin(tab, hash); break; } // 重复值操做 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } // 前面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; }
在文章的最后做者为你们整理了不少资料!包括java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书等等!
欢迎关注公众号:前程有光,领取!架构