ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用友秋招Java岗笔试全解析:核心考点、避坑指南与复习策略

用友秋招Java岗笔试全解析:核心考点、避坑指南与复习策略 2023年用友集团秋招Java岗笔试我是在十月中旬参加的那场线上统考。当时投的是用友网络的Java开发工程师笔试平台用的是牛客网全程摄像头监控两个小时内需要完成单选题、多选题、简答题和两道在线编程题。整体体感很直接用友的笔试没有那么卷算法但Java基础、框架原理和数据库的考察深度非常扎实没有真功夫只靠背题通过率会相当惨淡。这篇文章我不打算写成标准答案汇编而是结合当时真实的笔试回忆和后续复盘把用友Java岗笔试的命题逻辑、核心考点、常见坑位以及复习策略完整梳理一遍。无论你是准备投用友的Java岗还是想拿它作为企业级Java岗位笔试的参考样本这篇内容都能帮你少走很多弯路。1. 用友秋招Java笔试全景题量、结构与命题风格1.1 为什么说用友笔试跟互联网大厂不是一个路数先说结论用友的笔试考察重心明显偏向企业级应用开发而不是算法竞赛。我认识不少同学习惯了刷LeetCode拼手速结果在用友笔试里反而没有占到便宜因为它的选择题和简答题占比非常高编程题只占很小的一部分而且难度基本控制在LeetCode Medium偏下。用友作为国内老牌的企业服务厂商产品线覆盖ERP、财务云、人力云、供应链等领域。这意味着Java岗写的不只是业务CRUD还要面对大量复杂的企业业务模型、高并发对账、报表计算、多租户数据隔离这类场景。所以笔试题目非常贴近实际开发HashMap在并发场景下会出什么问题、Spring事务在什么情况下会失效、MySQL索引为什么选B树……这些问题不是背诵八股而是在考察你有没有真正写过生产代码。题型题量分值占比考察方向单选题20题40%Java基础、集合、并发、JVM、网络多选题10题20%框架原理、数据库、设计模式简答题2题20%Spring事务、JVM调优、场景设计编程题2题20%算法、数据结构、字符串处理从分值占比就能看出来选择和简答加起来直接占了80%。所以备考重点要放在核心知识体系的扎实度上而不是过度追求算法题难度。1.2 两个小时的时间分配策略我当时的做题顺序是先做选择题再做多选题然后直接跳去写编程题最后回头写简答题。这个顺序在复盘时被评为最合理的时间分配方式原因有三点选择题和多选题是条件反射型题目刚打开试卷时脑子最清醒正确率最高。编程题需要时间调试放在中间段做能够保证有充足时间处理边界情况。简答题不需要过强的逻辑连贯性只要知识点掌握到位随时可以快速输出。时间上我建议的选择题控制在25分钟内多选题15分钟两道编程题45分钟简答题留20分钟剩余15分钟检查。值得一提的是用友笔试题量看起来不大但多选题的陷阱非常多尤其是一些下列说法正确的是的题型必须逐项判断不能凭感觉选否则漏选错选都会扣分。1.3 关键词里的命题趋势信号从笔试结束后我搜集到的同学反馈来看2023年用友Java岗笔试出现了大量和Java面试八股文高度重合的题目比如面向对象三大特性的多态实现原理、HashMap的put流程、synchronized锁升级过程、Spring Bean的生命周期、MySQL的MVCC机制。这说明用友的笔试题库和主流Java面试题高度同源但也做了一些企业场景化的改编比如会问在ERP系统中如何用Redis实现分布式锁多租户场景下如何做数据隔离这类实际问题。这意味着备考用友笔试不需要去刷偏门冷门的知识点把主流八股文吃透吃细跟着Java学习路线把JavaSE、Java集合、并发、JVM、MySQL、Redis、Spring这七个大块复习扎实基本就能覆盖90%以上的考点。2. Java基础与集合高频考点扎实才是王道2.1 面向对象、String、异常……这些送分题别丢分用友笔试的第一部分单选题有不少题目是基础中的基础比如面向对象三大特性、重载与重写的区别、String和StringBuilder的区别。这类题看似简单但命题人非常喜欢在细节上挖坑我印象最深的一道题是下面哪种方式可以正确比较两个String对象的内容是否相等A. B. equals() C. hashCode() D. compareTo()这道题很多人会直接选B但严格来说D也是对的。compareTo()返回0时表示两个字符串相等所以正确答案是BD。这种多选按单选出的陷阱在笔试里非常多见答题时一定要把每个选项都验证一遍再落笔。另一个高频考点是String的不可变性与常量池的关系。用友考试里常考的原题方向是String s1 abc; String s2 new String(abc); s1 s2的结果是什么答案显然是false。原因是s1指向字符串常量池中的对象而s2在堆中新建了一个对象两者不是同一个引用。但更深一层的问题是s2.intern()之后呢intern()方法会去常量池中查找是否存在内容相同的字符串如果存在则返回常量池引用所以intern()后s1和s2的引用就相等了。Java集合框架中还有一个高频考察点ArrayList和LinkedList的适用场景。比如下面这道用友多选题的原型以下关于ArrayList和LinkedList的描述正确的是A. ArrayList底层是动态数组LinkedList底层是双向链表 B. ArrayList随机访问效率高于LinkedList C. LinkedList在中间插入元素的效率一定高于ArrayList D. ArrayList扩容时会创建新数组并复制旧数据答案是ABD。C选项是一个经典陷阱理论上LinkedList在中间插入只要改指针但实际上需要先遍历找到插入位置时间复杂度是O(n)并不一定高于ArrayList。这种题考察的不只是表面结论而是对数据结构底层实现的理解深度。2.2 HashMap八股全解从JDK7到JDK8的变化如果说用友笔试里一定要押一道题那一定是HashMap。我参加的那场笔试选择题考了HashMap的put流程简答题又考了JDK8中HashMap为什么线程不安全算是双重押注。这里把HashMap的核心机制完整过一遍按照笔试答题的标准格式来写。首先是put操作的完整流程面试和笔试都要求能背下来计算key的hash值通过(n - 1) hash计算出数组下标如果该位置为空直接放入新节点如果该位置不为空则判断链表头节点是否是同一个key如果是则覆盖value否则遍历链表找到相同key则覆盖找不到则在链表尾部插入新节点。JDK8中当链表长度超过8且数组长度大于等于64时链表会转换为红黑树树化的目的是把查询时间复杂度从O(n)降为O(log n)。第二个必须会的问题是为什么HashMap不安全。JDK7中并发put可能导致环形链表因为头插法在扩容时会逆序转移节点JDK8中改成了尾插法避免了环形链表问题但并发put时依然可能发生数据覆盖——两个线程同时拿到相同的数组下标一个put成功另一个put结果直接覆盖掉前一个丢失更新。所以笔试答题时要说清楚JDK8不是修复了线程安全问题只是把安全问题从死循环变成了数据覆盖和size计数不准。第三个关键点是扩容机制。HashMap的默认初始容量是16负载因子是0.75所以当元素个数超过16 * 0.75 12时触发扩容。每次扩容变成原来的两倍并且JDK8进行了优化扩容时不用重新计算hash只需要看原hash值新增的那个bit是0还是1如果是0就留在原位置如果是1就移动到原位置旧容量的位置。这个优化面试里已经考烂了但笔试中作为简答题出现时很多人反而说不到点上。2.3 ConcurrentHashMap与并发集合的考查套路用友笔试多选题里还出现了一道与ConcurrentHashMap相关的题目考点集中在JDK8的实现细节下列关于ConcurrentHashMap的说法正确的是A. JDK8中抛弃了分段锁使用CAS synchronized实现并发控制 B. put操作时若数组位置为空则使用CAS直接插入 C. synchronized只锁住链表或红黑树的头节点 D. size()统计元素个数时需要加全局锁正确答案是ABC。D选项是错的JDK8的size()通过baseCount和CounterCell累加实现整个过程是无锁的。这道题非常典型地反映了用友笔试的考察风格考点全部集中在JDK8之后的新实现而不是停留在JDK7的分段锁老黄历上。另一个容易被考到的是CopyOnWriteArrayList。它适合读多写少的场景写操作时复制整个数组到新数组在新数组上修改然后用volatile变量替换原数组引用。优点是读操作不需要加锁缺点也很明显写操作开销大且读取到的是旧数据。这里需要注意CopyOnWriteArrayList的迭代器是弱一致性的迭代过程中其他线程的修改不会反映到当前迭代器上这是并发的必备考点。3. 并发、JVM、Spring Boot八股背后必须会的为什么3.1 并发编程高频题从锁升级到线程池参数用友笔试的并发编程部分是整场考试中区分度最高的模块因为选择题不仅考概念还会搭配运行结果是什么这类需要真正理解并发机制的题目。先说synchronized的锁升级过程这是一个必背点无锁 → 偏向锁 → 轻量级锁 → 重量级锁。偏向锁是同一个线程多次获取同一把锁时不再进行CAS操作轻量级锁是在锁竞争不激烈时通过CAS自旋获取锁避免线程阻塞如果自旋次数超过阈值就升级为重量级锁阻塞其他线程。笔试中常见的变形题是synchronized (this)和synchronized (Class)的区别是什么前者锁的是当前实例对象后者锁的是整个类对象所以this锁只对当前实例有效而Class锁对所有实例都生效。这个知识点在简答题和场景题中很容易出现比如有两个实例对象两个线程分别调用它们的方法用synchronized(this)能不能互斥答案是不能因为锁的不是同一个对象。线程池是用友笔试的另一个重头戏核心必答内容是七个参数corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。具体流程是提交任务时先判断当前线程数是否小于核心线程数是则创建新线程执行否则尝试将任务放入阻塞队列如果队列满了再判断当前线程数是否小于最大线程数是则创建临时线程执行如果线程数已经达到最大值执行拒绝策略。这个流程必须完整写出来而且要注意一个容易忽视的细节线程池的初始创建时机是提交任务的时候而不是线程池创建的时候也就是说默认情况下创建ThreadPoolExecutor并不会立即创建核心线程除非调用prestartAllCoreThreads()方法。笔试中关于volatile的考察也比较多特别是在用友这种企业级场景下会很自然地延伸到volatile能不能保证原子性这个问题。volatile保证的是可见性和有序性但它不能保证复合操作的原子性比如i操作就不是线程安全的。同时volatile还有一个经典的使用场景是懒加载双重检查锁中的单例模式用volatile修饰单例实例防止指令重排导致拿到未初始化完成的对象。3.2 JVM内存、GC与OOM排查笔试里的压轴问JVM相关题目在2023年用友Java岗笔试中占的分值不低而且简答题直接出现了一道Java OOM有哪些类型如何排查的题目。这与热词中频繁出现的java: OutOfMemoryError: insufficient memory其实这条热词是JVM启动参数配置错误的报错不是标准OOM类型有直接关联说明大量同学在笔试环境或本地环境中都碰到过这个报错。先梳理JVM运行时数据区的五大块程序计数器、虚拟机栈、本地方法栈、堆、方法区。其中堆是OOM的高发区域虚拟机栈和本地方法栈对应StackOverflowError方法区在JDK8之后被元空间取代直接使用本地内存。笔试中常见的考察方式是给出一个场景让你判断OOM出在哪个区域比如一段循环代码中不断创建对象且不释放引用最终抛出OutOfMemoryError这个异常最可能发生在哪个区域A. 堆 B. 虚拟机栈 C. 方法区 D. 程序计数器答案是A堆。因为对象实例都存放在堆中无限制创建对象最终会导致堆内存溢出。GC相关的考察重点是如何判断对象可以被回收。核心机制是可达性分析算法从GC Roots出发通过引用链向下搜索任何不可达的对象都可以被回收。GC Roots包括虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、JNI引用的对象。这里尤其要注意引用计数法是一个已被JVM弃用的方案不能回答如果一个对象引用计数为0就回收因为循环引用场景下引用计数永远不为0。JVM调优参数的考察在笔试中也出现过比如-Xms和-Xmx分别代表堆的初始大小和最大大小-Xmn设置新生代大小-XX:MetaspaceSize设置元空间大小-XX:UseG1GC指定使用G1垃圾收集器。结合热词java: 警告: 源发行版 17 需要目标发行版 17这里补充一个很常见的环境问题在IDE中运行Java时报源发行版17需要目标发行版17是因为编译器和运行环境的JDK版本不一致需要在IDE中把Project Structure的SDK和语言级别统一设置为17。这个问题不是笔试考点但在做编程题时容易遇到提前知道怎么解决能避免浪费时间。3.3 Spring Boot与用友业务场景的关联考察用友笔试的简答题不会直接问Spring Boot的自动配置原理是什么这种干巴巴的问题而是会结合业务场景。比如我遇到的简答题是在使用Spring事务时什么情况下事务会失效。这个问题要想拿高分不能只列一两条建议按照以下维度完整展开访问权限问题如果事务方法被private修饰Spring通过CGLIB代理时无法增强private方法事务失效。方法自调用问题同类中一个方法调用另一个被Transactional修饰的方法由于调用发生在对象内部不经过代理对象事务失效。异常被吞掉问题事务方法捕获异常后没有抛出指定异常Spring感知不到事务需要回滚。数据库引擎不支持事务比如MySQL的MyISAM引擎本身不支持事务。传播行为设置问题如果传播行为是NOT_SUPPORTED事务会被挂起不生效。这道题之所以需要展开是因为它在实际的企业级开发中非常常见。用友的产品线里财务系统和供应链系统涉及大量的多表操作一旦事务控制不好数据一致性就会出大问题。所以笔试考察的不只是八股更是在看候选人有没有真实踩过这些坑。Spring Boot的自动配置原理也是高频考点备考时一定要把SpringBootApplication拆开理解它由SpringBootConfiguration、EnableAutoConfiguration和ComponentScan组合而成。其中EnableAutoConfiguration通过AutoConfigurationImportSelector类的getCandidateConfigurations()方法从META-INF/spring.factoriesSpring Boot 2.7之前或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsSpring Boot 2.7之后中加载所有自动配置类的名称再通过Conditional系列注解按条件装配。例如RedisAutoConfiguration类上的ConditionalOnClass(RedisOperations.class)只有在类路径下存在RedisOperations类时才会生效。笔试还考了Spring Bean的生命周期这里需要注意的是它的完整链路是实例化 → 属性赋值 → initializeBean初始化前后置处理器 → 初始化方法 → 使用 → 销毁。其中有两个关键扩展点是BeanPostProcessor#postProcessBeforeInitialization和postProcessAfterInitializationSpring的AOP代理就是在这两个方法中完成的。如果笔试问你Spring AOP底层原理核心是动态代理有接口时使用JDK动态代理没有接口时使用CGLIB代理JDK8中通过Proxy.newProxyInstance()生成代理对象CGLIB则是生成目标类的子类。4. 算法与手写代码实战两个小时的答题节奏4.1 高频算法题快速排序、二分、链表反转用友笔试的编程题一共两道我拿到的题目分别是按员工工资排序和字符串去重并统计出现次数。整体难度不高第一题其实就是在考察快速排序或者排序API的熟练度第二题考察的是HashMap的计数能力。但编程题不能只写核心逻辑需要写完整的方法定义、入参校验和返回值处理。快速排序是用友笔试和面试中最高频的手写算法因为它在排序计算、报表处理等企业场景中应用广泛。手写快速排序的关键是选基准值、分区、递归三步笔试环境下建议直接使用挖坑法来写代码简洁不容易出错public void quickSort(int[] arr, int left, int right) { if (left right) { return; } int pivot arr[left]; int l left; int r right; while (l r) { while (l r arr[r] pivot) { r--; } arr[l] arr[r]; while (l r arr[l] pivot) { l; } arr[r] arr[l]; } arr[l] pivot; quickSort(arr, left, l - 1); quickSort(arr, l 1, right); }代码中比较容易出现的bug是arr[r] pivot和arr[l] pivot的等号处理如果漏掉等号在遇到大量重复元素时会导致无限递归或者栈溢出。这是笔试环境中最容易踩的坑需要在写完后加上一组重复元素自测。二分查找也是高频考点笔试中一般不会单独出而是会结合有序数组中查找目标值的位置来考。标准写法中要注意的是mid left (right - left) / 2写成(left right) / 2在数值较大时可能溢出。第二类必练的是链表反转用友笔试中曾出现过反转单链表的变形题。递归写法代码虽然短但笔试环境下容易在边界条件上翻车我更推荐使用迭代写法public ListNode reverseList(ListNode head) { ListNode prev null; ListNode curr head; while (curr ! null) { ListNode nextTemp curr.next; curr.next prev; prev curr; curr nextTemp; } return prev; }注意这里必须先用nextTemp保存curr.next否则指针一断开后面的节点就丢了。这个错误几乎每个初学链表的同学都犯过笔试现场时间紧张更容易忽略所以在提交前一定要养成手动走一遍小规模数据的好习惯。4.2 编程题书写规范怎么让阅卷人一眼看懂在线笔试的编程题虽然没有人工阅卷环节但代码在运行时对输入输出格式有严格校验格式不符直接判0分。很多同学代码逻辑是对的却因为Scanner的使用姿势不对导致超时或者格式错误。用友笔试平台是牛客网模式输入需要自己写Scanner读取。细节上要注意一行读一个整数还是读两个整数需要用nextInt()还是nextLine()读完整数后是否有残留换行符这些都会影响程序行为。推荐的写法是先用Scanner sc new Scanner(System.in)获取输入然后按照题目给出的格式逐行读取所有输出使用System.out.println()。编程题的答题顺序建议是先花3分钟读题明确输入输出格式再花5分钟写核心逻辑最后留2分钟处理边界情况。边界情况至少要考虑4类空数组、单元素数组、全相同元素数组、已经有序的数组。这些是笔试中评测用例最爱设置的隐藏测试点漏掉任何一个都可能直接从部分通过变成未通过。4.3 与场景结合的算法题员工排序和字符串统计题目按员工工资排序虽然本质是排序但要拿满分还需要考虑到工资相同的员工按工号排序薪水可能是大整数型不能用int直接存。这类题目考察的是能否在业务约束下正确选择数据类型和排序规则。建议用Comparator实现多字段排序employees.sort(Comparator.comparing(Employee::getSalary) .thenComparing(Employee::getId));这里用到了Lambda表达式也是热词中lambda函数 java对应的知识点。Lambda表达式最核心的考点是函数式接口——只有一个抽象方法的接口比如Runnable、Comparator、Function、Consumer。笔试选择题中常考的是(x, y) - x y对应哪种函数式接口答案是BiFunctionInteger, Integer, Integer。字符串相关的编程题也出现过多次比如统计字符串中每个字符出现的次数并输出次数最多的字符。核心解法就是用HashMap遍历累加MapCharacter, Integer countMap new HashMap(); for (char c : s.toCharArray()) { countMap.put(c, countMap.getOrDefault(c, 0) 1); }这里推荐使用getOrDefault替代containsKey加get的两步判断代码更简洁。如果笔试要求按出现次数排序就先把entrySet转为List然后通过Collections.sort加Comparator完成排序。用友这种企业级应用笔试经常将字符串处理题包装成订单号统计日志级别统计等业务场景但核心解法不变。5. 常见问题与避坑经验过来人踩过的坑5.1 环境、编译、时间分配最容易翻车的地方说到笔试翻车现场最可惜的不是不会做而是会做却没时间或者没提交成功。第一个高发问题是环境准备。在线笔试对浏览器有要求建议提前一天用笔试通知里的链接测试设备确保摄像头、麦克风、网络都正常。笔试过程中不要切换浏览器标签页系统检测到跳出次数太多会直接判定作弊。第二个高发问题是JDK版本相关报错。编程题环境里如果本地写了var等新语法而在线编译器是JDK8就会直接编译失败。所以笔试写代码时尽量使用JDK8兼容的语法比如显式写上类型、不用var、不用java.time中的新APIJDK8本身支持LocalDate但要注意在线环境的具体JDK版本。另一个热词里提到的vscode运行java报错乱码在笔试中也遇到过本质上就是控制台编码和代码文件编码不一致通常是GBK和UTF-8互转导致。笔试平台一般使用UTF-8编码代码中不要出现中文字符串常量打印信息也尽量用英文可以彻底避免乱码。第三个高发问题是时间分配失衡。我认识一个同学选择题磨蹭了50分钟最后编程题只写了一道即使前面正确率再高总分也上不去。我的建议是单选控制在每题1分钟内不确定的先标记后跳过不要在一个选项上死磕。多选每题2分钟简答题每题10分钟编程题每题15分钟这是一套比较稳妥的节奏。5.2 八股文背诵的正确姿势理解底层而不是背结论用友笔试的题目很多看起来是八股文但光背结论远远不够因为命题人会设置各种变形和干扰项。举个例子如果你只背了HashMap线程不安全这个结论遇到哪些情况下HashMap线程不安全的多选题就会懵如果你理解了JDK8中并发put会发生数据覆盖的原理就能举一反三。我的建议是备考时采用结论 原理 例子三位一体的方式。以volatile不保证原子性为例结论是明确的原理是volatile只保证可见性和有序性没有加锁机制例子是多个线程同时执行count最终结果会小于预期。先理解例子再反推原理最后记住结论这样的记忆更加牢固。同时强烈建议在笔试前把所有高频手写题过一遍快速排序、冒泡排序、二分查找、单例模式双重检查锁写法、链表反转、用栈实现队列这六道题几乎覆盖了企业Java笔试的算法半壁江山。冒泡排序虽然理论复杂度高但用友这类企业笔试偶尔也会考察基础写法特别是要求优化冒泡排序——增加一个标志位当遍历一轮后没有发生交换时提前结束排序。5.3 结合用友的产品特性做场景化准备用友笔试的很多题目看起来是通用的Java面试题但真正拉开差距的是你能不能把通用知识点和用友的业务场景结合起来思考。比如考Redis缓存时会问在企业ERP系统中缓存击穿和缓存穿透有什么区别而不是单纯的什么是缓存穿透。考MySQL时会问多租户场景下如何设计数据隔离方案而不是什么是索引。这里有一个非常实用的准备方法投递用友之前花半小时了解它的核心产品。用友的产品集中在对公业务服务涉及财务核算、供应链管理、人力管理、制造管理等方向。这些场景意味着数据模型复杂、表关联多、数据量大、权限控制严格所以以下几个技术点是用友笔试超高频出现的MySQL索引失效的场景函数操作、隐式类型转换、符合最左前缀原则等。Redis分布式锁的可靠实现setnx 过期时间 唯一标识 Lua脚本释放锁。多租户数据隔离方案独立数据库、共享数据库独立Schema、共享表加租户ID字段三种方案各自的优劣。大数据量报表查询优化分库分表、读写分离、汇总表、搜索引擎。这些知识点在常规Java面试准备中也会涉及但用友笔试的题目会把它们包装到业务场景里。提前了解业务背景不仅笔试时有代入感后续面试中谈到项目经验也能更有针对性地展示自己的技术匹配度。5.4 笔试后的复盘从题目反推技术栈笔试结束后建议趁记忆还清晰时把遇到的题目整理成文档尤其是那些犹豫了很久或者答错的题。我当时考完就用20分钟把自己能回忆起来的题目全部写在备忘录里第二天逐题查漏补缺这个习惯让我后续的每一次面试都受益良多。复盘时不只是看正确答案还要问自己三个问题这个知识点我在项目中用过吗用友为什么会考这个如果面试官追问我能答到什么程度比如笔试考了String为什么不可变如果只是背答案因为final修饰的char数组就太浅了。深入一点的理解是String类被final修饰不可继承内部的value数组也是final且私有的没有提供任何修改数组内容的方法同时String对象在常量池中被缓存如果可变会导致常量池中的字符串被篡改影响所有引用该字符串的对象。这层逻辑才是笔试和面试官真正想看到的。我个人的体会是用友秋招Java岗笔试与其说是一场筛选考试不如说是一次技术基础的全面体检。它不会用偏题怪题来刁难你只要你扎扎实实把Java基础、集合、并发、JVM、Spring Boot、MySQL、Redis这几个模块吃透再配合一定的场景化思考通过笔试的把握是非常大的。最忌讳的是眼高手低——觉得HashMap原理好像懂了但真让你写put流程时写不清楚。笔试面前人人平等你多准备一分通过率就多一分。
返回列表