精华内容
下载资源
问答
  • Collections常用的静态方法 sort() 可以对集合进行排序,不能对复杂的集合排序,需要先制定排序规则(重写compareTo()方法) 实现一个类的对象之间比较大小 1.该类要重写Comparable接口的compareTo()方法,...

    Collection和Collections是啥关系?

    Collection是集合接口
    Collections是集合的操作类


    Collections中常用的静态方法

    sort()

    1.可以对集合进行排序,不能对复杂的集合排序,需要先制定排序规则(重写compareTo()方法)

    2.实现一个类的对象之间比较大小

    实现步骤

    1.该类要重写Comparable接口的compareTo()方法
    2.自定义比较规则
    返回值:相等,返回0;大于,返回1;小于,返回-1

    //实现Comparable接口
    public class Student implements Comparable 
    //重写compareTo()方法
    public int compareTo(Object Object){
        Student student = (Student)Object;//操作前必须强制转型
        if(this.sid<student.sid){
            return -1;
        }else if(this.sid>student.sid){
            return 1;
        }else {
            return 0;
        }
    }

    2.调用sort()方法

    //使用Collections中的sort()方法进行排序
    Collections.sort(stuSet);
    //for循环遍历集合
    for (int i=0;i<stuSet.size();i++){
        Student student = (Student) stuSet.get(i);
        System.out.println(student.getSid()+"--"+student.getName());
    }

    max()/min()
    binarySearch()
    reverse()

    展开全文
  • 提供排序,查找,反转,替换,复制,取最小,最大元素等功能 1.1、set 元素不能重复,使用equals确保对象一致性—&gt;实现类hashset treeset(有序) 只能通过迭代器(Iterator)来遍历元素 方法:add、...

    深入集合类(常用的集合类有哪些/比如List如何排序/集合的安全)

    1、collections框架(包括列表list,queue队列,set集合,stack栈,map键值对)

    提供排序,查找,反转,替换,复制,取最小,最大元素等功能

    1.1、set 元素不能重复,使用equals确保对象一致性—>实现类hashset treeset(有序)

    只能通过迭代器(Iterator)来遍历元素
    方法:add、contains、remove、clear

    特点
    1、HashSet类 是Set接口的一个子类,无序集合,采用hash存储,所以没有顺序,依赖HashMap来实现,可null;HashSet的数据存储在HashMap的map中,对应于map中的key
    2、TreeSet类 TreeSet实现SortedSet接口,有序集合;依赖 TreeMap来实现//插入一个子集,默认升序;不可null

    向TreeSet中插入数据

    			1、ArrayList<Integer> list = new ArrayList<Integer>(); list.add(300);   list.add(120);
    			2、new TreeSet<Integer>().addAll(list);
    

    1.2、list 有序 按进入的顺序存储,元素可以重复

    实现类
    1、linkedlist(双向链表,查找慢,插入快,不安全)
    2、arraylist(基于数组,查找快,插入慢,线程不安全)
    3、Stack 类: Stack继承自Vector,实现一个后进先出的堆栈(基于数组,安全)

    可以看到 ArrayList、Vector、LinkedList 集合类继承了 AbstractList 抽象类,而 AbstractList 实现了 List 接口,同时也继承了 AbstractCollection 抽象类。ArrayList、Vector、LinkedList 又根据自我定位,分别实现了各自的功能。ArrayList 和 Vector 使用了数组实现,这两者的实现原理差不多,LinkedList 使用了双向链表实现
    在这里插入图片描述

    Q1:关于ArrayyList的三道面试题?(20191004补充)

    id 题目 答案
    1 在查看 ArrayList 的实现类源码时,发现对象数组 elementData 使用了 transient 修饰,我们知道 transient 关键字修饰该属性,则表示该属性不会被序列化,然而我们并没有看到文档中说明 ArrayList 不能被序列化,这是为什么? 使用 transient 修饰数组,是防止对象数组被其他外部方法序列化。ArrayList 为了避免这些没有存储数据的内存空间被序列化,内部提供了两个私有方法 writeObject 以及 readObject 来自我完成序列化与反序列化,从而在序列化与反序列化数组时节省了空间和时间
    2 在使用 ArrayList 进行新增、删除时,经常被提醒“使用 ArrayList 做新增删除操作会影响效率”。那是不是 ArrayList 在大量新增元素的场景下效率就一定会变慢呢? 如果在初始化时就比较清楚存储数据的大小,就可以在 ArrayList 初始化时指定数组容量大小,并且在添加元素时,只在数组末尾添加元素,那么 ArrayList 在大量新增元素的场景下,性能并不会变差,反而比其他 List 集合的性能要好
    3 如果让你使用 for 循环以及迭代循环遍历一个 ArrayList,你会使用哪种方式呢?原因是什么? 由于 ArrayList 是基于数组实现的,所以在获取元素的时候是非常快捷的

    Q2:ArrayList和LinkedList内部的实现大致是怎样的?他们之间的区别和优缺点?看过源码!!!(掌握到源码级别,蚂蚁**)
    1.2.1、Arraylist解析:
    基于动态数组的数据结构,查找快,插入慢,每次增删元素顺序都会操作每个元素,线程不安全 初始10,扩容步长0.5,数组的复制)
    分别分析 ArrayList 的构造、add、remove、clear 方法的实现原理

    • 数据结构

      // 默认初始化容量
      private static final int DEFAULT_CAPACITY = 10;
      // 对象数组
      transient Object[] elementData;
      // 数组长度
      private int size;

    • 构造函数

      空参构造:array是一个Object[]类型,当我们new一个空参ArrayList的时候,系统内部使用了一个new Object[0]数组。
      带参构造1:该构造函数传入一个int值,该值作为数组的长度值
      带参构造2:调用构造函数的时候传入了一个Collection的子类

    • add方法 (两个重载:一种是直接将元素加到数组的末尾,另外一种是添加元素到任意位置)

      1、首先将成员变量array赋值给局部变量a,将成员变量size赋值给局部变量s。
      2、判断集合的长度s是否等于数组的长度,重新分配数组的时候需要计算新分配内存的空间大小
      3、将新添加的object对象作为数组的a[s]个元素
      4、修改集合长度size为s+1
      5、modCotun++
      6、return true

    • remove方法(两个重载)

      1、先将成员变量array和size赋值给局部变量a和s
      2、判断形参index是否大于等于集合的长度,如果成了则抛出运行时异常
      3、获取数组中脚标为index的对象result,该对象作为方法的返回值
      4、调用System的arraycopy函数,集合整体向前移动了一位
      5、最后一个元素设置为null
      6、重新给成员变量array和size赋值

    • clear方法

      如果集合长度不等于0,则将所有数组的值都设置为null,然后将成员变量size 设置为0即可,最后让修改记录数加1

    1.2.2、linkedlist解析:
    基于双向链表的数据结构,有一个内部类作为存放元素的单元,里面有三个属性,用来存放元素本身以及前后2个单元的引用(查找慢,会遍历大量元素,插入快,不安全)

    • 数据结构(LinkedList 定义了一个 Node 结构,Node 结构中包含了 3 个部分:元素内容 item、前指针 prev 以及后指针 next)
    private static class Node<E> {
            E item;
            Node<E> next;
            Node<E> prev;
     
            Node(Node<E> prev, E element, Node<E> next) {
                this.item = element;
                this.next = next;
                this.prev = prev;
            }
        }
    
    • LinkedList 实现类

      LinkedList 类实现了 List 接口、Deque 接口,同时继承了 AbstractSequentialList抽象类, LinkedList 既实现了 List 类型又有 Queue 类型的特点 ;LinkedList 也实现了 Cloneable 和 Serializable 接口,同 ArrayList 一样,可以实现克隆和序列化

    • LinkedList 属性(可以看到这三个属性都被 transient 修饰了,原因很简单,我们在序列化的时候不会只对头尾进行序列化,所以 LinkedList 也是自行实现 readObject 和 writeObject 进行序列化与反序列化)
    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;
    
    • LinkedList 遍历元素

      LinkedList 的获取元素操作实现跟 LinkedList 的删除元素操作基本类似,通过分前后半段来循环查找到对应的元素。但是通过这种方式来查询元素是非常低效的,特别是在 for 循环遍历的情况下,每一次循环都会去遍历半个 List。所以在 LinkedList 循环遍历时,我们可以使用 iterator 方式迭代循环,直接拿到我们的元素,而不需要通过循环查找 List

    1.2.3、总结:

    • 1.对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。

      对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;
      对LinkedList而言,这个开销是统一的,分配一个内部Entry对象

    • 2、在 ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。

    • 3、LinkedList不支持高效的随机元素访问

    • 4、ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间

    1.2.4、结论:

    性能测试 项目 结果 分析
    1.ArrayList 和 LinkedList 新增元素操作测试 1、从集合头部位置新增元素,2、从集合中间位置新增元素,3、从集合尾部位置新增元素 ArrayList>LinkedList,ArrayList<LinkedList,ArrayList<LinkedList 2、ArrayList 在添加元素到数组中间时,同样有部分数据需要复制重排,效率也不是很高;LinkedList 将元素添加到中间位置,是添加元素最低效率的,因为靠近中间位置,在添加元素之前的循环查找是遍历元素最多的操作,3、 LinkedList 中多了 new 对象以及变换指针指向对象的过程,所以效率要低于 ArrayList
    ArrayList 和 LinkedList 删除元素操作测试 1、从集合头部位置删除元素2、从集合中间位置删除元素3、从集合尾部位置删除元素 ArrayList>LinkedList,ArrayList<LinkedList,ArrayList<LinkedList 原因同上
    3.ArrayList 和 LinkedList 遍历元素操作测试 1、for(;;) 循环2、迭代器迭代循环 ArrayList<LinkedList,ArrayList≈LinkedList 因为 LinkedList 基于链表实现的,在使用 for 循环的时候,每一次 for 循环都会去遍历半个 List,所以严重影响了遍历的效率
    • 1、当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;

    • 2、当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了

    1.2.5、数组和arraylist的区别:

    • 1、数组可以包含基本类型和对象类型,arraylist只能包含对象类型

    • 2、数组大小固定,arraylist大小可以动态变化

    1.2.6、Arraylist与LinkedList区别

    Arraylist优点:基于动态数组的数据结构,因为地址连续,查询操作效率会比较高 缺点:插入和删除操作效率比较低
    LinkedList优点:基于链表的数据结构,地址是任意的,新增和删除操作占优势,适用于要头尾操作或插入指定位置 缺点:查询操作性能比较低

    1.3、map 键值对 键唯一,值可重复。

    实现类 简介
    hashmap 基于散列表,使用对象的hash值可以快速查询
    hashtable 同步的,线程安全的键值对,效率低
    TreeMap 根据key值进行升序排序的键值对;使用红黑树实现,按序排序
    synchronizedMap() 实现同步控制的键值对,一个静态内部类,实现了Map接口

    1.3.1、hashmap详解(基于散列表,使用对象的hash值可以快速查询,允许空键值,containskey,containsvalue不安全 默认16 *1.5 Iterator),

    HashMap实现原理,如何保证HashMap的线程安全?
    JDK7:位桶(Hash表)+链表的方式
    JDK8:位桶(Hash表)+链表/红黑树

    从 HashMap 的源码中,我们可以发现,HashMap 是由一个 Node 数组构成,每个 Node 包含了一个 key-value 键值对。 (20191004补充)

    transient Node<K,V>[] table;
    

    Node 类作为 HashMap 中的一个内部类,除了 key、value 两个属性外,还定义了一个 next 指针。当有哈希冲突时,HashMap 会用之前数组当中相同哈希值对应存储的 Node 对象,通过指针指向新增的相同哈希值的 Node 对象的引用。

    static class Node<K,V> implements Map.Entry<K,V> {
         final int hash;
         final K key;
         V value;
         Node<K,V> next;
    
         Node(int hash, K key, V value, Node<K,V> next) {
             this.hash = hash;
             this.key = key;
             this.value = value;
             this.next = next;
         }
    }
    

    HashMap 还有两个重要的属性:加载因子(loadFactor)和边界值(threshold)。在初始化 HashMap 时,就会涉及到这两个关键初始化参数。LoadFactor 属性是用来间接设置 Entry 数组(哈希表)的内存空间大小,在初始 HashMap 不设置参数的情况下,默认 LoadFactor 值为 0.75

    int threshold;
    final float loadFactor;
    

    1、初始容量表示哈希表的长度,初始是16
    2、哈希表中的条目数超出了加载因子0.75与当前容量的乘积时,则要对该哈希表进行 resize 操作
    3、加入键值对时,先判断当前已用数组长度是否大于等于阀值,如果大于等于,则进行扩容,容量扩为原容量2倍

    hashmap的数据结构?
    在这里插入图片描述

    • hashmap的特点?

      1、HashMap处理hash冲突时,会首先存放在链表中去,链表的长度达到阀值8,链表就将转换成红黑树;小于6,转链表,优化存储速度。O(lgn)
      2、HashMap底层维护一个数组,数组中的存储Entry对象组成的链表
      3、Map中的key,value则以Entry的形式存放在数组中,通过key的hashCode计算
      4、map m = collections.synchronizedMap(new hashmap()),返回同步的map,有hashmap所有的方法
      5、concurrenthashmap 系统自带的线程安全的HashMap

    • ConcurrentHashMap和synchronizedMap两者区别:

      1、ConcurrentHashMap的实现更加精细,在性能以及安全性方面更优
      同步操作精确控制到node,其他线程,仍然可以对node执行某些操作
      多个读操作几乎总可以并发地执行
      例如:在遍历map时,其他线程试图对map进行数据修改,不会抛出ConcurrentModificationException***
      2.synchronizedMap()可以接收任意Map实例,实现Map的同步,如TreeMap实现排序,Map<String, Object> map2 = Collections.synchronizedMap(new TreeMap<String, Object>());
      而ConcurrentHashMap只能是HashMap

    1.3.2、讲一下hashmap中put方法过程?

    HashMap 添加元素优化:初始化完成后,HashMap 就可以使用 put() 方法添加键值对了。从下面源码可以看出,当程序将一个 key-value 对添加到 HashMap 中,程序首先会根据该 key 的 hashCode() 返回值,再通过 hash() 方法计算出 hash 值,再通过 putVal 方法中的 (n - 1) & hash 决定该 Node 的存储位置。

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    

    hash函数是怎么实现的? ****

    1、散列算法 hash&(length-1)
    2、hash的高16bit和低16bit做了一个异或
    3、(n-1)&hash 得到下标
    4、使用&代替取模,实现了均匀的散列,但效率要高很多,与运算比取模的效率高(由于计算机组成原理)

    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
        // 通过 putVal 方法中的 (n - 1) & hash 决定该 Node 的存储位置
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
    

    1、对key求hash值,然后再计算下标
    2、如果没有碰撞,直接放入桶中;(key相同,替换value值)
    3、如果碰撞了,以链表的方式链接到后面(key不同,用链表存)
    4、如果链表长度超过阈值8,就把链表转成红黑树
    5、如果节点已经存在就替换旧值;
    6、如果桶满了(容量*加载因子),就需要resize
    在这里插入图片描述

    • HashMap中put操作的源码?
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
        Node<K,V>[] tab;
        Node<K,V> p;
        int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
        //1、判断当table为null或者tab的长度为0时,即table尚未初始化,此时通过 resize() 方法得到初始化的 table
        n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
        //1.1、此处通过(n - 1) & hash 计算出的值作为 tab 的下标 i,并另 p 表示 tab[i],也就是该链表第一个节点的位置。并判断 p 是否为 null
       		tab[i] = newNode(hash, key, value, null);
        	//1.1.1、当 p 为 null 时,表明 tab[i] 上没有任何元素,那么接下来就 new 第一个 Node 节点,调用 newNode 方法返回新节点赋值给 tab[i]
        else {
    		//2.1 下面进入 p 不为 null 的情况,有三种情况:p 为链表节点;p 为红黑树节点;p 是链表节点但长度为临界长度 TREEIFY_THRESHOLD,再插入任何元素就要变成红黑树了。
            Node<K,V> e;
            K k;
            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
    		//2.1.1HashMap 中判断 key 相同的条件是 key 的 hash 相同,并且符合 equals 方法。这里判断了 p.key 是否和插入的 key 相等,如果相等,则将 p 的引用赋给 e
                e = p;
            else if (p instanceof TreeNode)
    			//2.1.2 现在开始了第一种情况,p 是红黑树节点,那么肯定插入后仍然是红黑树节点,所以我们直接强制转型 p 后调用 TreeNode.putTreeVal 方法,返回的引用赋给 e
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
    			//2.1.3 接下里就是 p 为链表节点的情形,也就是上述说的另外两类情况:插入后还是链表 / 插入后转红黑树。另外,上行转型代码也说明了 TreeNode 是 Node 的一个子类
                for (int binCount = 0; ; ++binCount) {
    				// 我们需要一个计数器来计算当前链表的元素个数,并遍历链表,binCount 就是这个计数器
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) 
    						// 插入成功后,要判断是否需要转换为红黑树,因为插入后链表长度加 1,而 binCount 并不包含新节点,所以判断时要将临界阈值减 1
                            treeifyBin(tab, hash);
    					// 当新长度满足转换条件时,调用 treeifyBin 方法,将该链表转换为红黑树
                        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;
    }
    

    1.3.3、为什么哈希表的容量一定要是2的整数次幂?

    第二种问法:实际应用中,我们设置初始容量,一般得是 2 的整数次幂。你知道原因吗?(面试题:2的幂次方减1后每一位都是1,让数组每一个位置都能添加到元素。减少哈希冲突,均匀分布元素

    h&(length-1),散列的均匀、空间利用充足
    1、2的整数次幂为偶数,length-1为奇数,最后一位是1,保证h&(length-1)的最后一位可能为0或1,保证散列的均匀性,且空间利用充足
    2、length为奇数的话,length-1为偶数,最后一位是0,h&(length-1)的最后一位为0,浪费了近一半的空间
    3、h是key的hashcode的高16位和低16位的异或运算,之所以异或,是因为生成0/1的概率相等

    1.3.4、hashmap怎样解决冲突、讲一下扩容过程,假设一个值在原数组中,现在移动了新数组,位置肯定变了,那么怎么定位到这个值在新数组中的位置?

    新建一个HashMap的底层数组,而后调用transfer方法,将就HashMap的全部元素添加到新HashMap
    要重新计算元素在新的数组中的索引位置

    方式 细节
    在 JDK1.7 中 HashMap 整个扩容过程就是分别取出数组元素,一般该元素是最后一个放入链表中的元素,然后遍历以该元素为头的单向链表元素,依据每个被遍历元素的 hash 值计算其在新数组中的下标,然后进行交换。这样的扩容方式会将原来哈希冲突的单向链表尾部变成扩容后单向链表的头部。
    在 JDK 1.8 中 HashMap 对扩容操作做了优化。由于扩容数组的长度是 2 倍关系,所以对于假设初始 tableSize = 4 要扩容到 8 来说就是 0100 到 1000 的变化(左移一位就是 2 倍),在扩容中只用判断原来的 hash 值和左移动的一位(newtable 的值)按位与操作是 0 或 1 就行,0 的话索引不变,1 的话索引变成原索引加上扩容前数组。

    1.3.5、子类:

    1、LinkedHashMap维护了插入的先后顺序【FIFO】,适合LRU算法做缓存(最近最少使用)
    2、WeakHashMap是改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收

    1.3.6、hash冲突如何解决?

    方式有很多,比如,开放定址法、再哈希函数法和链地址法

    方法 细节 是否推荐
    开放定址法 当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把 key 存放到冲突位置的空位置上去。这种方法存在着很多缺点,例如,查找、扩容等,所以我不建议你作为解决哈希冲突的首选。
    再哈希法 在同义词产生地址冲突时再计算另一个哈希函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但却增加了计算时间
    链地址法 先找到下标i,KEY值找Entry对象,新值存放在数组中,旧值在新值的链表上,将存放在数组中的Entry设置为新值的next 推荐

    1.3.7、get操作:

    对key进行null检查:如果key是null,返回table[0]位置元素
    key的hashcode()方法被调用,然后计算hash值
    indexFor(hash,table.length)用来计算要获取的Entry对象在table数组中的精确的位置
    遍历链表,调用equals()方法检查key相等性,如果equals()方法返回true,get方法返回Entry对象的value,否则,返回null

    性能上:在链表长度过长的情况下,性能将明显降低,红黑树的使用很好地解决了这个问题,使得查询的平均复杂度降低到了 O(log(n)),链表越长,使用黑红树替换后的查询效率提升就越明显。

    1.3.8、hashmap从1.7到1.8,新元素为什么要从头部调整到尾部呢?

    id 原因
    1、 为了防止死循环(hashmap扩容导致死循环的问题。后续再整理)
    2、 JDK1.7是考虑新增数据大多数是热点数据,所以考虑放在链表头位置,也就是数组中,这样可以提高查询效率,但这种方式会出现插入数据是逆序的。在JDK1.8开始hashmap链表在节点长度达到8之后会变成红黑树,这样一来在数组后节点长度不断增加时,遍历一次的次数就会少很多,相比头插法而言,尾插法操作额外的遍历消耗已经小很多了。

    1.3.9 hashmap的put和get的时间复杂度算多少啊?

    hashmap的最优时间复杂度是O(1),而最坏时间复杂度是O(n)
    在没有产生hash冲突的情况下,查询和插入的时间复杂度是O(1);
    而产生hash冲突的情况下,如果是最终插入到链表,链表的插入时间复杂度为O(1),而查询的时候,时间复杂度为O(n);
    在产生hash冲突的情况下,如果最终插入的是红黑树,插入和查询的平均时间复杂度是O(logn)。

    2、Iterator:遍历集合

    next方法返回第一个元素,hasNext判断容器是否还有元素,remove删除元素,遍历时对容器进行增加,删除操作会导致并发修改异常,
    解决方法:把要删除的对象保存到一个集合中,遍历结束调用removeAll方法,或是Iterator.remove方法。
    多线程中:并发异常如何避免:concurrenthashmap,copyonwritearraylist,线程安全;或是迭代器遍历时,放在synchronized代码块中,性能有影响。
    子类 listIterator:继承自Iterator,可以双向遍历,支持元素的修改

    3、collection集合接口 实现接口的类list和set

    4、collections包装类,提供一系列静态方法实现集合的搜索,排序,线程安全化。

    4.1、比如List如何排序?

    使用集合工具包的collections.sort()方法排序,可以重写里面的compare方法
    

    4.2、集合的安全?(在并发编程中常用)

    Collections工具类提供了相关的API
    Collections.synchronizedList(list)
    Collections.synchronizedCollection©
    Collections.synchronizedMap(m)

    5、 容器中的设计模式?

    5.1、迭代器模式

    Collection实现了Iterable接口,其中的iterator()方法能够产生一个Iterator对象,通过这个对象就可以迭代遍历Collection中的元素
    从JDK1.5之后可以使用foreach方法来遍历实现了Iterable接口的聚合对象
    

    List list = new ArrayList<>();
    list.add(“a”);list.add(“b”);
    for(String item:list){syso(item);}

    5.2、适配器模式

    java.util.Arrays#asList()可以把数组类型转换为List类型
    应该注意的是asList()的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的包装类型数组
    

    Integer[] arr = {1, 2, 3}; List list = Arrays.asList(arr);//数组转为list
    List list= Arrays.asList(1,2,3);

    展开全文
  • 数组有哪些常用方法

    2020-05-17 11:30:52
    答案: ... sort 数组排序 map/forEach/filter/indexOf/includes/slice/splice 详细解析: 1. Array.push(),向数组末尾添加一个或多个元素,并返回新数组长度。原数组改变。 .

    答案:

    • push 末尾添加

    • pop 末尾删除

    • shift 首部删除

    • unshift 首部添加

    • concat 数组合并

    • join 数组元素 通过连接符 连接

    • reverse 数组反转

    • sort 数组排序

    • map/forEach/filter/indexOf/includes/slice/splice

     

    详细解析:

    1. Array.push(),向数组的末尾添加一个或多个元素,并返回新的数组长度。原数组改变。

    2. Array.pop(),删除并返回数组的最后一个元素,若该数组为空,则返回undefined。原数组改变。

    3. Array.unshift(),向数组的开头添加一个或多个元素,并返回新的数组长度。原数组改变。

    4. Array.shift(),删除数组的第一项,并返回第一个元素的值。若该数组为空,则返回undefined。原数组改变。

     

    5. Array.concat(arr1,arr2...),合并两个或多个数组,生成一个新的数组。原数组不变。

    6. Array.join(),将数组的每一项用指定字符连接形成一个字符串。默认连接字符为 “,” 逗号。

    7. Array.reverse(),将数组倒序。原数组改变。

    8. Array.sort(),对数组元素进行排序。按照字符串UniCode码排序,原数组改变。

      ①从小到大

      

      ②从大到小

       

      ③按照数组对象中的某个值进行排序

      

      

     9.Array.map(function),原数组的每一项执行函数后,返回一个新的数组。原数组不变。(注意该方法和forEach的区别)。

    10.Array.slice(start,end),从start开始,end之前结束,不到end;如果不给end值,从start开始到数组结束。start可以给负值,-1表示数组最后位置,-2表示倒数第二个,以此类推,顾前不顾后。

      

    11.Array.splice(index,howmany,arr1,arr2...) ,删除元素并添加元素,从index位置开始删除howmany个元素,并将arr1、arr2...数据从index位置依次插入。howmany为0时,则不删除元素。原数组改变。

    对数组进行增删改

    增加:ary.splice(n,0,m)从索引n开始删除0项,把m或者更多的内容插入到索引n的前面

    返回空数组

    修改:ary.splice(n,x,m)从索引n开始删除x个,m替换删除的部分

    把原有内容删除掉,然后用新内容替换掉

    删除:ary.splice(n,m) 从索引n开始删除m个内容

    (如果第二个参数省略,则从n删除到末尾)

    返回删除的新数组,原有数组改变

    //增加
    let ary6_z = [33,44,55,66,77,88];
    ary6_z.splice(2,0,'a','b')
    console.log(ary6_z); //[33, 44, "a", "b", 55, 66, 77, 88]
    
    //修改
    let ary6_x = [33,44,55,66,77,88];
    ary6_x.splice(1,2,'x','y');
    console.log(ary6_x); //[33, "x", "y", 66, 77, 88]
    
    //删除
    let ary6_s = [33,44,55,66,77,88];
    console.log(ary6.splice(3,2)); //[66, 77]
    console.log(ary6_s.splice(3)); //[66, 77, 88]

    12.Array.forEach(function),用于调用数组的每个元素,并将元素传递给回调函数。原数组不变。(注意该方法和map的区别,若直接打印Array.forEach,结果为undefined)。

    let arr = ['a','b','c','d']; 
    let item = arr.forEach(function(item,index,arr){
        console.log(item,index,arr);
    });

    13.Array.filter(function),过滤数组中,符合条件的元素并返回一个新的数组。

     

    14.Array.every(function),对数组中的每一项进行判断,若都符合则返回true,否则返回false。

    15.Array.some(function),对数组中的每一项进行判断,若都不符合则返回false,否则返回true。

    16.Array.indexOf(function),检测当前值在数组中第一次出现的位置索引,未找到返回-1。

    let ary9 = ['a','b','c','d','e','a','f'];   
    console.log(ary9.indexOf('c')); //2
    console.log(ary9.indexOf('a',3)); //5

    17.Array.includes(),判断一个数组是否包含一个指定的值

    let ary13 = ['a','b','c','d']; 
    console.log(ary13.includes('c')); //true
    console.log(ary13.includes(2)); //false

    18.Array.reduce(function),reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

     

     

    展开全文
  • js 数组有哪些常用方法

    千次阅读 2020-06-30 11:10:20
    1、push 向数组末尾添加一个或更多元素,并返回新...7、sort 数组排序即最小值位于最前面,最大值排在最后面 8、slice 从数组返回选定元素slice表示截取,slice(start,end)不改变原数组,返回新数组 9、splice

    1、push 向数组的末尾添加一个或更多元素,并返回新的长度。
    2、pop 删除并返回数组的最后一个元素
    3、shift 删除并返回数组的第一个元素
    4、concat 连接两个或更多的数组,并返回结果。
    5、join 把数组的所有元素链接成一个字符串。元素通过指定的分隔符进行分隔。
    6、reverse 数组元素反转
    7、sort 数组排序即最小的值位于最前面,最大的值排在最后面
    8、slice 从数组返回选定的元素slice表示截取,slice(start,end)不改变原数组,返回新数组
    9、splice 删除元素,并向数组添加新元素。splice(start,length,item),从某个位置开始删除多个元素,并可以插入新的元素,可以实现删除、插入和替换。会改变原数组。
    10、toString 把数组转换为字符串,并返回结果。
    11、toLocaleString 把数组转换为本地数组,并返回结果。
    12、unshift 向数组的开头添加一个或更多元素,并返回新的长度。
    13、valueOf 返回数组对象的原始值
    14、indexOf 查找数组中的元素,存在返回下标值,不存在返回-1。从数组的开头(位置 0)开始向后查找。
    15、lastIndexOf 查找数组中的元素,存在返回下标值,不存在返回-1。从数组的末尾位置开始向后查找。
    16、includes 查找数组中的元素,存在返回true 不存在返回false
    17、forEach arr.forEach(function(item,index){})对数组进行遍历循环,对数组中的每一项运行给定函数。这个方法没有返回值。参数都function类型,默认有传参。
    18、map arr.map(function(){})指对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
    19、filter arr.filter(function() {}):过滤功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。
    20、every arr.every(function(){})判断数组中每一项都是否满足条件,只有所有项都满足条件,才会返回true。
    21、some arr.some(function(){})判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。

    如有错误,请留言指正,如有遗漏,请留言补充。欢迎大神留言,

    展开全文
  • 常用的集合有哪些

    万次阅读 多人点赞 2018-09-07 15:56:11
    常用的三大类集合:Set、List、Map。 1 Set 1) Set 集合属于单列集合,不允许包含重复元素; 2) 判断元素是否重复的标准为对象的 equals 方法,存在时返回 false,不存在返回 true; 3) 元素的排序规则,由相应...
  • 对于这个问题,老生常谈,但是也不容易记,找一篇比较好的分享给大家 但是大家尽量做到能徒手写出来常见的排序... 排序方法 时间复杂度 空间复杂度 稳定性 复杂性 ...
  • ls:列出当前目录内容或指定目录 ...ls –u 配合-t选项,显示并按atime从新到旧排序 ls –U 按目录存放顺序显示 ls –X 按文件后缀排序 touch 格式:touch [OPTION]… FILE… -a 仅改变 atime和cti
  • 2.Collections的常用方法有哪些? 方法名:Collections.addAll(list, 5,6,9,11,30,32,45) <方法功能描述>:可以往list集合中一次加入多个元素 方法名:Collections.max(list) <方法功能描述>:求
  • 首先我们来看一下常见的排序算法有哪些,以及这些算法的时间复杂度是什么等级的。 这几个字段是对整个算法的评估,这样方便我们在选择算法的时候能够有所依据,以达到合理科学的选取合适的算法。 接下来,分别...
  • 列表元素是可变,它具有添加、删除、搜索、排序等多种方法。1、一维列表可以在创建列表时候一次性定义所有元素,也可以以后再向列表里面添加:name = ["zhangsan","lisi","wangwu"] print name ['zhangsan',...
  • js实现数字排序方法

    2020-07-25 01:31:01
    常用算法有哪些呢? 冒泡排序 1.冒泡排序 这因该算我们熟悉第一个排序方法吧,就是每次比较两个数字,通过判断进行前后交换,知道数组中没有可以交换数,算法结束 function maopao(arr) { // 英语不好 var len ...
  • DataStructure---排序算法(七) 一,【前言】 排序算法是所有AI, ... 1,常用的排序算法有哪些? 2,插入排序分为哪些? 3,选择排序稳定吗? 4,shell排序和归并排序有什么关联吗? 5, 这些排序算法都怎么进行选择? 二,
  • 3dmax常用快捷键命令有哪些?在使用3dmax进行作图渲染过程之中,熟练掌握一些命令快捷键位置,能够大大提升我们工作效率。同时,根据自己使用习惯,自定义常用快捷键命令,也可以加快我们作图速度。一起...
  • 公司新人培训过程中,我们还是偏重于 1.基础语法夯实、方法的有效定义、方法重载及重写规范、 2.多态理解和应用、不同接口实现(函数接口对应Lambda表达式应用...引用类型对象比较、排序之类方式方法。 9
  • 展开全部Python常用的30个脚本:1、冒32313133353236313431303231363533e58685e5aeb931333433646531泡排序2、计算x的n次方的方法3、计算a*a + b*b + c*c + ……4、计算阶乘 n!5、列出当前目录下的所有文件和目录名6...
  • 继续补充一些常用的内建函数1、sorted排序函数,reverse=True从大到小排序a = [2,7,4,90,45]res = sorted(a,reverse=True)print(res)打印结果:[90, 45, 7, 4, 2]注意区分sorted和sort什么区别?下方我用sort方法...
  • 比如用户要匹配查询,前几天我们学过,match匹配和term匹配两种常用的方式。 这些在Java中又是哪些方法来对应呢? 原生的方法可以是使用,但是比较麻烦,这里使用springdata提供的自定义方法。 1自定义方法...
  • C++中string用法 string字符串使用方法 听语音 | 浏览:22380 | ...string类的常用方法有哪些。string查找替换、分割字符串、比较、截取、类型转换、排序等功能都提供了强大
  • 转载自百度经验 :... string类的常用方法有哪些。string查找替换、分割字符串、比较、截取、类型转换、排序等功能都提供了强大处理函数,可以代替字符数组来使用。  1. 定义和构造初始化    string 提
  • 常用工具类

    2019-09-16 20:14:31
    Java中有许多应用类,这些类定义静态方法可以解决很多常见问题。下面是通过5万个开源项目统计...浏览这个类可以看看有哪些功能不用再自己写了。 非常有用。 点击尾部阅读原文链接可以看到具体使用示例。 1、...
  • -常用的汇总函数有哪些?-练习: 汇总分析2.对数据分组-分组背后的分析方法是什么?-如何对数据分组?-练习:常用面试题3.对分组结果指定条件-如何为分组结果指定条件?-理解SQL运行顺序-练习常见面试题4.如何用SQL...
  • 7、使用索引索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多速度检索特定行,尤其是在查询语句当中包含MAX(),MIN()和ORDERBY这些命令时候,性能提高更为明显。那该对哪些字段建立...
  • ①输入参数②选定规则③输出返回值1.2常用的汇总函数有哪些?Count() MAX() MIN() SUM() AVG() COUNT(DISTINCT()) 1.3练习:汇总分析 . 2.对数据分组2.1分组背后的分析方法是什么?分组→操作→结果2.2如何对数据...
  • MYSQL常用命令大全

    2011-05-30 13:31:24
    MySql的用户管理是通过 User表来实现的,添加新用户常用的方法有两个,一是在User表插入相应的数据行,同时设置相应的权限;二是通过GRANT命令创建具有某种权限的用户。其中GRANT的常用用法如下: grant all on mydb...
  • assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    ◆ Windows 95/98常用的FAT 32文件系统:vfat ; ◆ Win NT/2000 的文件系统:ntfs ; ◆ OS/2用的文件系统:hpfs; ◆ Linux用的文件系统:ext2、ext3; ◆ CD-ROM光盘用的文件系统:iso9660。 虽然vfat是指...
  • 高级Java程序员必须要会知识点

    千次阅读 2017-12-07 13:49:33
    常用的集合类有哪些?比如List如何排序? ArrayList和LinkedList内部的实现大致是怎样的?他们之间的区别和各自适应的场景是什么? 内存溢出是怎么回事? ClassLoader有什么用? ==和equals的区别? hashCode方法的...
  • Java常见面试题总结

    2020-05-16 14:01:12
    2:Object类的方法有哪些? 3:final修饰类,变量,及方法有什么用? 4:Java中常说万物皆对象,举例说明? 5:抽象类和普通类有什么区别?抽象类和接口有什么区别? 6:重载和重写有什么区别? 7:常用...
  • 2.常用的集合类有哪些?具有哪些特性?是否有序?是否可以为null?是否排序?是否重复? 每个集合类底层的数据存储结构?3.Comparator和Comparable接口的作用和异同点?4.HashMap的底层实现的数据结构?1.7- 数组+...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 151
精华内容 60
关键字:

常用的排序方法有哪些