[八股大全]Java常见集合类篇

1.集合基础知识

1.Java集合有哪几种?

Java集合类主要由两个接口CollectionMap派生出来的,

一个是 Collection接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口:ListSetQueue(念q)。

哪些是线程安全哪些线程不安全?

java.util包下的集合类大部分都是线程不安全的,例如我们常用的HashSet、TreeSet、ArrayList、LinkedList、ArrayDeque、HashMap、TreeMap,这些都是线程不安全的集合类,但是它们的优点是**性能好。**如果需要使用线程安全的集合类,则可以使用Collections工具类提供的synchronizedXxx()方法,将这些集合类包装成线程安全的集合类。java.util包下也有线程安全的集合类,例如Vector、Hashtable。这些集合类都是比较古老的API,虽然**实现了线程安全,但是性能很差。**所以即便是需要使用线程安全的集合类,也建议将线程不安全的集合类包装成线程安全集合类的方式,而不是直接使用这些古老的API。从Java5开始,Java在java.util.concurrent包下提供了大量支持高效并发访问的集合类,它们既能包装良好的访问性能,有能包装线程安全。这些集合类可以分为两部分,它们的特征如下:

  • 以Concurrent开头的集合类: 以Concurrent开头的集合类代表了支持并发访问的集合,它们可以支持多个线程并发写入访问, 这些写入线程的所有操作都是线程安全的,但读取操作不必锁定。以Concurrent开头的集合类采 用了更复杂的算法来保证永远不会锁住整个集合,因此在并发写入时有较好的性能。
  • 以CopyOnWrite开头的集合类: 以CopyOnWrite开头的集合类采用复制底层数组的方式来实现写操作。当线程对此类集合执行读 取操作时,线程将会直接读取集合本身,无须加锁与阻塞。当线程对此类集合执行写入操作时,集 合会在底层复制一份新的数组,接下来对新的数组执行写入操作。由于对集合的写入操作都是对数 组的副本执行操作,因此它是线程安全的。

2.集合的具体实现类

List

  • ArrayListObject[] 数组。
  • VectorObject[] 数组。
  • LinkedList:双向链表(JDK1.6 之前为循环链表,JDK1.7 取消了循环)。

Map

  • HashMap:JDK1.8 之前 HashMap 由数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。
  • LinkedHashMapLinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
  • Hashtable:数组+链表组成的,数组是 Hashtable 的主体,链表则是主要为了解决哈希冲突而存在的。
  • TreeMap:红黑树(自平衡的排序二叉树)。

Set

  • HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素。
  • LinkedHashSet: LinkedHashSetHashSet 的子类,并且其内部是通过 LinkedHashMap 来实现的。
  • TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树)。

Queue

  • PriorityQueue: Object[] 数组来实现小顶堆。
  • DelayQueue:PriorityQueue
  • ArrayDeque: 可扩容动态双向数组。

3.说说 List, Set, Queue, Map 四者的区别?

Java中的集合类主要由Collection和Map这两个接口派生而出,其中Collection接口又派生出三个子接口,分别是Set、List、Queue。所有的Java集合类,都是Set、List、Queue、Map这四个接口的实现类,这四个接口将集合分成了四大类,其中

  • Set代表无序的,元素不可重复的集合;
  • List代表有序的,元素可以重复的集合;
  • Queue代表先进先出(FIFO)的队列;
  • Map代表具有映射关系(key-value)的集合。

4.为什么要使用集合?

因为在实际开发中,存储的数据类型多种多样且数量不确定。这时,Java 集合就派上用场了。与数组相比,Java 集合提供了更灵活、更有效的方法来存储多个数据对象。Java 集合框架中的各种集合类和接口可以存储不同类型和数量的对象,同时还具有多样化的操作方式。相较于数组,Java 集合的优势在于它们的大小可变、支持泛型、具有内建算法等。总的来说,Java 集合提高了数据的存储和处理灵活性,可以更好地适应现代软件开发中多样化的数据需求,并支持高质量的代码编写。

5.什么是fail fast快速失败机制?

快速失败(fail-fast)是Java集合框架中的一种错误检测机制

Fail-fast 机制主要用于确保集合在遍历过程中不被修改,从而保证数据的一致性和稳定性。

当多个线程对同一个ArrayList进行操作时,如果一个线程在遍历该集合的过程中,另一个线程同时尝试修改它(例如添加、删除元素),那么遍历线程会抛出ConcurrentModificationException异常。这种机制旨在防止并发修改导致的数据不一致问题。

6.什么是fail safe安全失败机制?

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。

缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

7.如何让一个集合不能被修改?

可以采用Collections包下的unmodifiableMap/unmodifiableList/unmodifiableSet方法,通过这个方法返回的集合,是不可以修改的。如果修改的话,会抛出 java.lang.UnsupportedOperationException异常。

List<String> list = new ArrayList<>();
list.add("x");
Collection<String> clist = Collections.unmodifiableCollection(list);
clist.add("y"); // 运行时此行报错
System.out.println(list. size());

对于List/Set/Map集合,Collections包都有相应的支持。

那使用final关键字进行修饰可以实现吗?

答案是不可以。

final关键字修饰的成员变量如果是是引用类型的话,则表示这个引用的地址值是不能改变的,但是这个引用所指向的对象里面的内容还是可以改变的。

而集合类都是引用类型,用final修饰的话,集合里面的内容还是可以修改的。

引用类型有哪些?

在Java中,引用类型主要包括类(Class)、接口(Interface)、数组(Array)以及基于这些结构的其他数据类型如字符串(String)和枚举类型(Enum)

Java将数据类型主要分为两大类:基本数据类型和引用数据类型。基本数据类型包括byte、short、int、long、float、double、char和boolean,它们直接存储值而非对象的引用。引用类型的变量则存储的是对象在内存中的地址,即引用了对象的位置。

2.List

-1.List有哪些类?

0.什么是ArrayList?

ArrayList 的底层是动态数组,它的容量能动态增长。在添加大量元素前,应用可以使用ensureCapacity操作增加 ArrayList 实例的容量。ArrayList 继承了 AbstractList ,并实现了 List 接口

0.有哪些线程安全的List?

参考答案

  • Vector Vector是比较古老的API,虽然保证了线程安全,但是由于效率低一般不建议使用。
  • Collections.SynchronizedList SynchronizedList是Collections的内部类,Collections提供了synchronizedList方法,可以将一个 线程不安全的List包装成线程安全的List,即SynchronizedList。它比Vector有更好的扩展性和兼 容性,但是它所有的方法都带有同步锁,也不是性能最优的List。
  • CopyOnWriteArrayList CopyOnWriteArrayList是Java 1.5在java.util.concurrent包下增加的类,它采用复制底层数组的方 式来实现写操作。当线程对此类集合执行读取操作时,线程将会直接读取集合本身,无须加锁与阻 塞。当线程对此类集合执行写入操作时,集合会在底层复制一份新的数组,接下来对新的数组执行 写入操作。由于对集合的写入操作都是对数组的副本执行操作,因此它是线程安全的。在所有线程 安全的List中,它是性能最优的方案。

1.ArrayList 和 Array(数组)的区别?

ArrayList 内部基于动态数组实现,比 Array(静态数组) 使用起来更加灵活:

  • ArrayList会根据实际存储的元素动态地扩容或缩容,而 Array 被创建之后就不能改变它的长度了。
  • ArrayList 允许你使用泛型来确保类型安全,Array 则不可以。
  • ArrayList 中只能存储对象。对于基本类型数据,需要使用其对应的包装类(如 Integer、Double 等)。Array 可以直接存储基本类型数据,也可以存储对象。
  • ArrayList 支持插入、删除、遍历等常见操作,并且提供了丰富的 API 操作方法,比如 add()remove()等。Array 只是一个固定长度的数组,只能按照下标访问其中的元素,不具备动态添加、删除元素的能力。
  • ArrayList创建时不需要指定大小,而Array创建时必须指定大小

2.ArrayList 和 Vector 的区别?

  • ArrayListList 的主要实现类,底层使用 Object[]存储,适用于频繁的查找工作,线程不安全 。
  • VectorList 的古老实现类,底层使用Object[] 存储,线程安全。
  • ArrayList在内存不够时扩容为原来的1.5倍,Vector是扩容为原来的2倍。

3.ArrayList 可以添加 null 值吗?

ArrayList 中可以存储任何类型的对象,包括 null 值。

4.Arraylist 与 LinkedList的区别

  • ArrayList的实现是基于数组,LinkedList的实现是基于双向链表;
  • 对于随机访问ArrayList要优于LinkedList,ArrayList可以根据下标以O(1)时间复杂度对元素进行随 机访问,而LinkedList的每一个元素都依靠地址指针和它后一个元素连接在一起,查找某个元素的 时间复杂度是O(N);
  • 对于插入和删除操作,LinkedList要优于ArrayList,因为当元素被添加到LinkedList任意位置的时 候,不需要像ArrayList那样重新计算大小或者是更新索引;
  • LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个 指向前一个元素,一个指向后一个元素

5.ArrayList扩容原理

ArrayList有三种构造方法,无参构造方法将创建一个空的ArrayList,其内部使用一个默认容量为10的空数组初始化。如果通过指定初始容量来构造ArrayList,那么会创建一个具有该初始容量的数组。第三种构造方法允许传入一个集合,并将其所有元素添加到ArrayList中。

  • 无参构造方法扩容过程如下

ArrayList的底层是动态数组,默认第一次插入元素时创建大小为10的数组。当调用add方法添加一个元素时,首先会确保当前ArrayList维护的数组具有存储新元素的能力。如果数组的容量不足以存储新元素,那么就会通过grow方法进行扩容扩容的方式是将数组的容量扩大到原来的1.5倍然后将原数组的数据复制到新的数组中。最后,将新元素添加到数组的末尾

6. 面试题-ArrayList list=new ArrayList(10)中的list扩容几次

在ArrayList的源码中提供了一个带参数的构造方法,这个参数就是指定的集合初始长度,所以给了一个10的参数,就是指定了集合的初始长度是10,这里面并没有扩容。

7.谈谈CopyOnWriteArrayList的原理

CopyOnWriteArrayList是Java并发包里提供的并发类,简单来说它就是一个线程安全且读操作无锁的ArrayListCopyOnWriteArrayList允许线程并发访问读操作,这个时候是没有加锁限制的,性能较高。正如其名字一样,在写操作时会复制一份新的List,在新的List上完成写操作,然后再将原引用指向新的List。这样就保证了写操作的线程安全。

  • 优点:读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。在遍历传统的 List时,若中途有别的线程对其进行修改,则会抛出ConcurrentModificationException异常。而 CopyOnWriteArrayList由于其"读写分离"的思想,遍历和修改操作分别作用在不同的List容器,所 以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了。
  • 缺点:一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力 较大,可能会引起频繁GC。二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读 和写的强一致性。而CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用在新老不同 容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。

7.LinkedList 为什么不能实现 RandomAccess 接口?

RandomAccess 是一个标记接口,用来表明实现该接口的类支持随机访问(即可以通过索引快速访问元素)。由于 LinkedList 底层数据结构是链表,内存地址不连续,只能通过指针来定位,不支持随机快速访问,所以不能实现 RandomAccess 接口

8.怎么在遍历 ArrayList 时移除一个元素?

foreach删除会导致快速失败问题,可以使用迭代器的 remove() 方法。

Iterator itr = list.iterator();
while(itr.hasNext()) {
      if(itr.next().equals("jay") {
        itr.remove();
      }
}

9.什么是ArrayList的快速失败fail fast机制

ArrayList的快速失败(fail-fast)是Java集合框架中的一种错误检测机制

当多个线程对同一个ArrayList进行操作时,如果一个线程在遍历该集合的过程中,另一个线程同时尝试修改它(例如添加、删除元素),那么遍历线程会抛出ConcurrentModificationException异常。Fail-fast 机制主要用于确保集合在遍历过程中不被修改,从而保证数据的一致性和稳定性。

10.如何实现数组和List之间的转换

数组转list,可以使用jdk自动的一个工具类Arrars,里面有一个asList方法可以转换为数组

List 转数组,可以直接调用list中的toArray方法、,需要给一个参数,指定数组的类型,需要指定数组的长度。

11.用Arrays.asList转List后,如果修改了数组内容,list受影响吗?List用toArray转数组后,如果修改了List内容,数组受影响吗

Arrays.asList转换list之后,如果修改了数组的内容,list会受影响,因为它的底层使用的Arrays类中的一个内部类ArrayList来构造的集合,在这个集合的构造器中,把我们传入的这个集合进行了包装而已,最终指向的都是同一个内存地址

list用了toArray转数组后,如果修改了list内容,数组不会影响,当调用了toArray以后,在底层是它是进行了数组的拷贝,跟原来的元素就没啥关系了,所以即使list修改了以后,数组也不受影响。

12.ArrayList 和 LinkedList 不是线程安全的,你们在项目中是如何解决这个的线程安全问题的?

第一:我们使用这个集合,优先在方法内使用,定义为局部变量,这样的话,就不会出现线程安全问题。

第二:如果非要在成员变量中使用的话,可以使用线程安全的集合来替代

ArrayList可以用CopyOnWriteArrayList

LinkedList 换成ConcurrentLinkedQueue来使用

3.Map相关面试题

0.Map有哪些类?

Map接口有很多实现类,其中比较常用的有HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap。

对于不需要排序的场景,优先考虑使用HashMap,因为它是性能最好的Map实现。如果需要保证线程安全,则可以使用ConcurrentHashMap。它的性能好于Hashtable,因为它在put时采用分段锁/CAS的加锁机制,而不是像Hashtable那样,无论是put还是get都做同步处理。对于需要排序的场景,如果需要按插入顺序排序则可以使用LinkedHashMap,如果需要将key按自然顺序排列甚至是自定义顺序排列,则可以选择TreeMap。如果需要保证线程安全,则可以使用Collections工具类将上述实现类包装成线程安全的Map。

TreeMap 基于红黑树实现。

HashMap 1.7基于哈希表实现,1.8基于数组+链表+红黑树。

HashTable 和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。它是遗留类,不应该去使用它。现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高(1.7 ConcurrentHashMap 引入了分段锁, 1.8 引入了红黑树)。

LinkedHashMap 使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。

1.HashMap 和 Hashtable 的区别

  • 线程是否安全:HashMap 是非线程安全的,Hashtable 是线程安全的,因为 Hashtable 内部的方法基本都经过synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);
  • 效率: 因为线程安全的问题,HashMap 要比 Hashtable 效率高一点。另外,Hashtable 基本被淘汰,不要在代码中使用它;
  • 对 Null key 和 Null value 的支持:HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个;Hashtable 不允许有 null 键和 null 值,否则会抛出 NullPointerException
  • 初始容量大小和每次扩充容量大小的不同: ① 创建时如果不指定容量初始值,Hashtable 默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍。② 创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小(HashMap 中的tableSizeFor()方法保证,下面给出了源代码)。也就是说 HashMap 总是使用 2 的幂作为哈希表的大小,后面会介绍到为什么是 2 的幂次方。
  • 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树),以减少搜索时间(后文中我会结合源码对这一过程进行分析)。Hashtable 没有这样的机制。

2.HashSet与HashMap的区别

(1)HashSet实现了Set接口, 仅存储对象; HashMap实现了 Map接口, 存储的是键值对.

(2)HashSet底层其实是用HashMap实现存储的, HashSet封装了一系列HashMap的方法. 依靠HashMap来存储元素值,(利用hashMap的key键进行存储), 而value值默认为Object对象. 所以HashSet也不允许出现重复值, 判断标准和HashMap判断标准相同, 两个元素的hashCode相等并且通过equals()方法返回true.

4.HashMap的底层实现(jdk1.7和jdk1.8有区别)

  • jdk1.7

JDK7中的HashMap,是基于数组+链表来实现的,它的底层维护一个Entry数组。它会根据计算的hashCode将对应的KV键值对存储到该数组中,一旦发生hashCode冲突,那么就会将该KV键值对放到对应的已有元素的后面, 此时便形成了一个链表式的存储结构。

JDK7中HashMap的实现方案有一个明显的缺点,即当Hash冲突严重时,在桶上形成的链表会变得越来越长,这样在查询时的效率就会越来越低,其时间复杂度为O(N)。

  • jak1.8

JDK8中的HashMap,是基于数组+链表+红黑树来实现的,它的底层维护一个Node数组。当链表长度大于阈值(默认为 8)外加数组长度大于64时时,将链表转化为红黑树,以减少搜索时间。这么做主要是在查询 的时间复杂度上进行优化,链表为O(N),而红黑树一直是O(logN),可以大大的提高查找性能。

1.线性探测法和链地址法

线性探测法是开放地址法的一种,用于处理哈希表中的冲突问题

线性探测法的核心在于解决哈希冲突时不采用链表,而是通过探测散列表中的下一个位置来寻找空位。具体来说,如果一个关键字通过散列函数计算的地址已经被占用,它会尝试下一个地址,即当前地址加一(也可以考虑为负数或固定步长,视情况而定),直到找到一个空位为止。这种方法在实际操作中简单且易于实现,但当哈希表较为拥挤时,可能会导致很多空闲位置之间出现很多“堆积”,增加了平均查找时间。

链地址法则是将具有相同哈希值的所有元素链接在同一个链表中

链地址法也被称为拉链法,它采用了不同的策略来解决哈希冲突。在这个方法中,每个哈希到同一个值的元素都会被插入到对应哈希值下的链表中。这意味着如果多个元素的哈希值相同,它们会被放在同一个链表里,以此来区分这些具有相同哈希值的元素。链地址法的优点是可以减少在插入和查找过程中的平均比较次数,因为每次比较的都是同义词节点。然而,这种方法需要额外的空间来存储指针信息。

总之,这两种方法各有利弊,在不同的场景下可能会选择不同的方法来优化性能。线性探测法更适合于哈希冲突较少时使用,而链地址法适合于处理大量冲突的情况。在实际应用中,选择哪种方法取决于具体的需求和场景。

2.红黑树

1.红黑树的介绍

(1)概述

红黑树(Red Black Tree):也是一种自平衡的二叉搜索树(BST),之前叫做平衡二叉B树(Symmetric Binary B-Tree)

(2)红黑树的特质

性质1:节点要么是红色,要么是黑色

性质2:根节点是黑色

性质3:叶子节点都是黑色的空节点

性质4:红黑树中红色节点的子节点都是黑色

性质5:从任一节点到叶子节点的所有路径都包含相同数目的黑色节点

在添加或删除节点的时候,如果不符合这些性质会发生旋转,以达到所有的性质,保证红黑树的平衡

(3)红黑树的复杂度

  • 查找: 红黑树也是一棵BST(二叉搜索树)树,查找操作的时间复杂度为:O(log n)
  • 添加: 添加先要从根节点开始找到元素添加的位置,时间复杂度O(log n)添加完成后涉及到复杂度为O(1)的旋转调整操作故整体复杂度为:O(log n)
  • 删除: 首先从根节点开始找到被删除元素的位置,时间复杂度O(log n)删除完成后涉及到复杂度为O(1)的旋转调整操作故整体复杂度为:O(log n)

2.为什么选红黑树,和二叉搜索树、AVL树(平衡二叉树)有什么区别?

  • 二叉搜索树:在二叉搜索树中,左子节点的值小于根节点的值,右子节点的值大于根节点的值。这使得二叉搜索树在查找操作上具有优势。然而**,二叉搜索树可能退化为线性结构,即链**表,当数据插入顺序有序或接近有序时,其查找效率会大大降低,时间复杂度可能达到O(n)。
  • AVL树:是一种高度平衡的二叉搜索树,它要求每个节点的左右子树的高度差不超过1。这种严格的平衡条件使得AVL树在查找操作上具有很高的效率,时间复杂度为O(log n)。然而,为了维护这种严格的平衡,AVL树在插入和删除操作时需要进行频繁的旋转调整,这增加了维护成本。因此,AVL树适合用于查找操作频繁但插入和删除操作较少的场景。
  • 红黑树:**红黑树是一种近似平衡的二叉搜索树,它通过一系列性质(如节点颜色、黑高)来维护树的平衡。与AVL树相比,红黑树的平衡条件相对宽松,因此在插入和删除操作时的维护成本较低。**虽然红黑树的查找效率略低于AVL树,但其综合性能较好,适用于各种操作(插入、删除和查找)都较频繁的场景。此外,红黑树的高度近似为2log n,在实际应用中表现出良好的性能。

3.在解决 hash 冲突的时候,为什么选择先用链表,再转红黑树?

**因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡,而单链表不需要,所以元素的插入操作非常高效。所以,当元素个数小于8个的时候,采用链表结构可以保证查询性能。**而当元素个数大于8个的时候并且数组容量大于等于64,会采用红黑树结构。因为红黑树搜索时间复杂度是 O(logn),而链表是 O(n),在n比较大的时候,使用红黑树可以加快查询速度。

4.为什么链表改为红黑树的阈值是 8?

理想情况下使用随机的哈希码,容器中节点分布在 hash 桶中的频率遵循泊松分布,按照泊松分布的计算公式计算出了桶中元素个数和概率的对照表,可以看到链表中元素个数为 8 时的概率已经非常小,再多的就更少了,所以原作者在选择链表元素个数时选择了 8,是根据概率统计而选择的。

5.红黑树会退化为O(n)的查找时间复杂度吗

红黑树理论上不会退化为O(n)的查

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

抽象带蓝子的八股大全专栏 文章被收录于专栏

我的笔记专栏,内有自己整理的八股知识笔记和算法刷题笔记,我会不断通过他人和自己的面经来更新和完善自己的八股笔记。专栏每增加一篇文章费用就会上涨一点,如果你喜欢的话建议你尽早订阅。内有超详细苍穹外卖话术!后续还会更新其他项目和我的实习经历的话术!敬请期待!

全部评论
11.12日已更新,订阅我专栏后可进入我的专栏里用md格式侧边栏看该笔记体验感更好!
点赞 回复 分享
发布于 2024-11-12 21:36 湖南

相关推荐

跟这公司的程序员对接的时候确实心累➕奇葩,没遇到过这么逆天的东西,后面我都懒得喷了甚至想笑我就来讲讲经典的几件事吧1.文档里面我们写好了我们要求的字段,对面总是漏传让我一次又一次发消息去确实对接,每次跟我说弄好了一看就少了几个,文档中写了不能为空值的字段每次都很多味空,弄的很多数据不对。我跟他们说,以后返回数据直接看着文档就行了,但一直不听人话,每次都把工作交到我这边来2.ok,上面的事情我忍了,毕竟我还有我们自己的文档,可是有些时候要用到对面公司的接口,我叫他们写个调用示例在文档里面一直不弄,催了好几天去大群艾特他,他领导在里面所以他就干活了,他不是直接填文档,而是甩了一个公司内部文档给我,叫我自己看。好好好,那我就自己看吧,ok我就用他的格式调用然后失败了,问他为什么,没人回复硬生生软磨硬泡了几天,然后还是在大群当着他领导面艾特他终于填了文档。ok这些我都忍了反正我是实习生,你拖就拖呗交付不了不是我的责任我就慢慢来就是了,反正你把文档填好就行了,我就一直看对方的参数错误一直debug。没事没事,反正习惯了。3.我对接遇到的最逆天的人就在20天前出现了。我说我要个xx文档对应的xx接口一直不鸟我,我就去大群艾特他,然后被领导看见后他发了一个文件给我说这就是接口请看一下,我点开一看这是什么清朝遗产的JSP实体类我就问他这是接口吗&nbsp;他说是的,逆天到让人发指&nbsp;连接口是啥都不知道。也就是说他把一个java的掺杂着jdp实体类发给我,让我看着他的实体类字段去调他的接口。我是神仙吗?我看着java的实体类能猜出他的内网➕端口➕接口路径甚至知道传的参数,然后把那个接口试出来?are&nbsp;you&nbsp;kidding&nbsp;me?我是什么赛博生物,能通过一个java实体类直接精准定位到你们公司的内网甚至直接定位到我要的那个端口吗?对于碳基生物来说确实难做到,可能他是赛博生物习惯了,但对于我这种还没完全进化的人来说确实有点超前了4.一个公司的是jsp我能理解,但他们的请求格式是什么urlencoding,我们网关必须是json格式,我问他能不能换成json,他直接想都不想就说不行。我火气上来了我说不行就全都做不了,他就去看了就说《我要要对字段修改方法修改讨论一下进行评估》,甚至一个电话过来阴阳我。就是他发那个jsp实体类的时候我叫他填接口,他连借口是啥都不知道。一过来就是《我们都是搞技术的》,《你不会不懂吧》什么什么的。就那种越心虚的人越喜欢强调某些东西,然后我说填接口文档不是你的工作吗?他说难道这是我的工作吗,我真的是南蚌,跟这个蠢货一点话都不想说。然后后面我们这边大佬出面压他,他才说ooo能搞什么的,才把接口文档填上了,但是实话实说,跟那种蠢人说话真的会减少自己的寿命5.之前说了,这家公司的程序员一直拖进度,然后各种不写文档让我主动去说,然后我就破防了,我有20天对接20个接口然后一直改,就因为对面不讲清楚。例如这个jsp哥,有个接口文档叫他填他不填,然后有个接口是他跟另一个平台对接的,那个女的也是逆天。我问她检查一下字段,她就说有事有事,我叫填接口她又把她们文档给我说看这个来,okok我来。点开文档一看又没有url,又是一个顶级的赛博生物,可惜这个赛博生物终究还是退化了,在我顾问连续逼问下终于填了url,阻止了我努力往赛博生物进化的趋势。但这个赛博生物甩锅倒是一流,先前不是说字段返回要根据我们文档来吗,我叫她确认一下她不理我,一共有25-28个字段,也就是这个b要我用我的人眼去一个一个找那些字段没对上,这明明对方程序员返回json的时候参照我们文档就行。我破防了,我问那个人然后她装死,顾问一个电话发过去让她共享一个一个核对&nbsp;发现少了7个字段。她就开始说《这字段我们要继续讨论一下》我顾问就质问她说《这不是一个月前就讨论好的吗?为啥你们没弄?》然后她就啥话都不说了6.经过这些事情各位也知道这家公司的程序员有多逆天了,几乎周围的人都知道我有多讨厌对接这家公司的蠢货了,因为每次他们一干蠢事装死推锅我就会说wtf这帮人怎么能蠢成这样。其实在我开骂的两个星期后我右边又来了个实习生&nbsp;他一开始在跟前端对接,还没接触那帮逆天的人,但是后面他跟对方接触10天后也直接开骂了。我来讲讲这哥们遇到的逆天的事情7.他对接那个女的5天没回他,在周五的时候直接质问他为什么一直不弄,但是他一直在弄但是遇到了某些错误这个必须对方解决在周一就说了。然后一直催,周五的时候对方的xxn直接在群里语气不好的开喷,然后说为什么我们不搞。然后就开始打电话一直说是我们问题,一开始顾问还好声好气地跟她说以后你们的需求改了能不能提前说,你们改了我们这边按照旧的做好了又不知道。她就说《我做了,这是你们的问题》然后那个实习生是在受不了了,把截图聊天记录全部甩给她,5天前就叫她弄了她不弄现在卡着时间点过来推锅,对面技术人员本来也在那喷,后面发现是自家xxn无理取闹也不说话了。8.这个不是更逆天的就在这两周&nbsp;他周三的时候跟我说,对面的人他周一发的消息周三都没已读。我说你赶紧保存下来省的下一次又来bb你,果不其然,星期五的时候对方又来问责说为什么没开发,直接把他那3-4天未读的截图发过去又不说话了。真的太逆天了只能说见证物种多样性了,我说的东西还是冰山一角,这个公司包容性太强了,例如要个接口给我发jsp,要他们开个权限让我自己ping,然后说不是他们的问题。而且他们喜欢拉小群,小群里没大领导他就在那偷懒推锅,反正我是实习生我直接在大群当着他领导面艾特他,他就会屁颠屁颠地说我们在小群里面讨论吧😅这家公司的包容性真的极强,我本来确实对那种程序员35岁危机很焦虑的,想着都不容易,但我叫对方发个url给我对方给我发个java实体类那一刻,我真的想劝告这家公司的高层让他把自家技术人员都换个血,因为是在是太逆天了。jsp哥,5天已读不回哥,打电话推锅姐,文档不填偷懒姐……只能说本来我组就我一个实习生,另一个实习生进来同样跟我一起喷,我想说这确实不是我们问题了,是这家公司的包容性太强了。赛博生物jsp哥尤其逆天,他确实是搞技术的,他的技术方向是&nbsp;让我升级成和他一样的赛博生物,可惜我就算进化到碳基生物的极限&nbsp;也不如他的jsp推演出借口的脑回路的一丝,毕竟人的思维做不到这么超脱,也就赛博生物可以了 #职场吐槽大会# #牛客创作赏金赛# #我的岗位说明书# #无语# #逆天#
点赞 评论 收藏
分享
2024-11-26 18:08
已编辑
蚌埠坦克学院 Java
科大讯飞 消费者 n*14
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
2024-12-01 12:01
快手 后端 23*16 本科双一流
点赞 评论 收藏
分享
评论
6
29
分享
牛客网
牛客企业服务