ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用友秋招Java笔试题解析:从基础语法到JVM与并发

2026/8/31 11:30:57 拓冰建站 浏览量
用友秋招Java笔试题解析:从基础语法到JVM与并发 秋招季节又到了后台不少同学在问用友这类老牌企业级软件公司的Java笔试题该怎么准备。说实话看到用友2018秋招Java笔试题五这个标题很多人第一反应是去找原题答案但真正把题目刷过一遍之后你会发现这套题最大的价值不是让你背住那几十道题的标准答案而是它把Java后端笔试最常考的几块内容——基础语法、集合框架、JVM内存、多线程、算法手写——全部浓缩在了一套卷子里。用友的笔试不像互联网大厂那样动不动就出系统设计或大数据场景题它的题风偏传统、偏扎实反而更像一面镜子能把基本功是否过关照得清清楚楚。这篇文章我就以这套题为引子把Java秋招笔试里最容易出现的几类题目拆开讲讲包括答题思路、容易踩的坑、以及我在实际工作中回头看这些知识点时的理解。顺便说一句这篇文章不只是给准备笔试的人看的。就算你已经在写业务代码了重新用笔试的视角审视一遍这些基础也会发现很多平时没有真正想透的地方。我尽量按照一套完整笔试试卷的模块顺序来讲方便你对照着自己的薄弱环节去补。1. 用友笔试的特点为什么Java基础题占了大半壁江山1.1 从笔试结构反推企业用人画像用友是做ERP、财务软件、云服务起家的核心产品线包括U8系列、NC系列、YonBIP等这些系统有一个共同特点业务逻辑复杂、数据一致性要求高、系统需要长期稳定运行。这种产品形态决定了他们在招Java开发时最看重的是候选人能不能写出健壮、可维护、不容易出线上事故的代码。所以你看他们往年的笔试题很少会出请描述一下你在项目中如何用Redis做分布式锁这类纯经验题更多是考String、ArrayList、HashMap、异常处理这些最底层的东西。原因很简单这些基础的掌握程度直接决定了你写的业务代码在极端情况下会不会出问题。比如一个财务系统里日期格式化错误导致对账不平一个并发场景下HashMap扩容导致CPU 100%这些事故追根溯源全是基础不牢。还有一个特点是用友的笔试普遍题量不小、时间偏紧。我记得当年的卷子大概有选择题、简答题、编程题三大块单选题覆盖的面很广从Java语法到数据库SQL都有涉及。这种出题方式说明他们更想考察知识面的广度而不是某一两个方向的深度。所以准备的时候不要只盯着一本《Java编程思想》看MySQL、Spring基础、设计模式这些也要过一遍。1.2 高频题型的分布规律我根据这些年网上流传的用友笔试回忆版和同类企业笔试题整理了一个大致分布。单选多选主要集中在语法细节、集合类源码行为、异常与断言、基本数据类型转换简答题通常有两三道常见方向是垃圾回收机制简述、HashMap实现原理、多线程通信方式编程题一般是一道算法题加一道SQL题算法题难度不会超过LeetCode中等但很考验手写代码的熟练度。这里要提醒一句很多同学觉得选择题简单随便蒙一蒙就过了这是大忌。用友这种传统软件公司的笔试选择题往往答对得分、答错倒扣分或者有明确的正确率门槛。因为系统是自动阅卷的选择题分数是进入面试的硬门槛反而是编程题因为评分标准宽松不太会因为一两个小错误直接刷人。所以策略上应该是选择题保准确率编程题保完整度。2. Java核心基础题从语法表层到JVM底层2.1 字符串与集合框架的经典陷阱题字符串、集合这两块是Java笔试题里出场率最高的因为代码里每天都在用但很多人都是会用不会懂。来我先放几道典型的题你可以先自己想想答案再对照后面的解析。第一道String a abc; String b new String(abc);问a b的结果是什么a.equals(b)的结果又是什么。第二道ListString list Arrays.asList(a, b, c); list.add(d);这段代码会不会报错。第三道HashMap的默认初始容量是多少加载因子是多少扩容阈值是多少。a b这个题考的是字符串常量池和对象引用的区别。字面量abc会放入常量池new String(abc)会在堆上新建一个对象两者引用地址不同所以结果是false。但equals比较的是值所以结果是true。我面试过不少人能答出和equals的区别但问到为什么new String(abc)会创建两个对象就卡住了。其实严格来说如果常量池里没有abc那么new String(abc)会创建两个对象一个在常量池一个在堆上。这背后是JVM的内存结构问题笔试里经常连着一起考。Arrays.asList返回的是一个固定长度的内部类ArrayList不是java.util.ArrayList所以调用add方法会抛UnsupportedOperationException。这个题很多人答错因为平时根本不会在这上面调用 add。但如果看过源码你就知道Arrays.asList返回的是Arrays类里的一个私有静态内部类它继承自AbstractList却没有重写add和remove方法。这个题目考的不是你会不会用List而是你有没有看过源码的习惯。HashMap的默认初始容量是16加载因子0.75扩容阈值是12。这三组数字最好能背下来并且知道它们是怎么配合工作的当元素数量超过12时HashMap会扩容到原来的两倍。这里还有一个很容易被忽略的细节JDK 8之后引入的红黑树机制链表长度超过8且数组容量大于等于64时会树化但如果数组容量不够64即使链表长度超过8也只会扩容而不是树化。2.2 面向对象与异常机制答案背后的设计思想笔试里有一类题看起来是考概念实际上是在考你对面向对象设计原则的理解程度。比如接口和抽象类的区别这个题几乎每次笔试都有但大多数人的回答就停留在接口多继承、抽象类单继承接口有默认方法这种语法层面。更好的答法是往设计思想上靠抽象类描述的是是什么接口描述的是能做什么抽象类适合抽取公共代码、避免重复接口适合定义行为规范、实现解耦。我见过一个答得不错的版本是这样说的Java中一个类只能继承一个抽象类但可以实现多个接口所以接口更利于系统的扩展和维护。比如一个支付系统定义PayService接口然后有AlipayServiceImpl、WechatPayServiceImpl等多个实现类后续新增支付方式只需要新增实现类不会影响已有逻辑。这种回答就把语法和实际应用联系起来阅卷人一看就知道你理解到了设计层面。异常机制也是常考的内容。常见题目有受检异常和非受检异常的区别finally块里return会覆盖try块里的return吗自定义异常应该继承什么类。这些题目的核心考点其实是对异常是控制流的一部分这个观念的理解。finally块里如果写了return它会覆盖try或者catch块里的return值。这是因为Java字节码层面finally块的代码会被复制到每个返回路径的前面执行。所以阿里巴巴开发规范里明确禁止在finally块中使用return我在评审代码时也经常因为这个跟同事争论。如果你在笔试里遇到这道题最好答完结果之后补一句实际开发中应该避免在finally里写return否则会破坏异常传递掩盖真实的错误信息。这句话加上去马上就跟普通考生拉开了差距。3. 排序与算法题笔试中真正拉开分差的部分3.1 冒泡排序的变体与手写要求用友这类公司的编程题不会像字节那样考hard级别的DP或者复杂图论冒泡排序、二分查找、单链表反转、字符串去重这类基本功题目出现的概率非常高。但正因为题目简单反而更容易暴露问题手写代码的规范性、边界条件处理、时间空间复杂度的分析能力。冒泡排序是考得最多的一个。别觉得它简单我见过太多人写冒泡排序时出现以下几种错误外层循环写了for (int i 0; i arr.length; i)内层循环又写了for (int j 0; j arr.length - 1; j)最后结果虽然能排出来但白白多了很多无效比较还有人写内层循环时边界条件算错导致数组越界异常。规范写法应该是外层循环记录未排序区间内层循环从0遍历到arr.length - 1 - i因为每一轮排序都会把当前区间最大值冒到最后最后一位置就不需要再参与比较了。这里我还想分享一个笔试里的加分写法冒泡排序的优化版。就是加一个swapped标志位如果内层循环一轮下来没有任何交换说明数组已经有序直接结束排序。这个优化在最坏情况下时间复杂度还是O(n^2)但最好情况下能降到O(n)。我在实际项目里虽然不会手写冒泡排序但用这个思路去理解类似数据基本有序时如何减少比较次数的问题帮助很大。3.2 快排实现中的边界问题与优化快速排序在笔试里出现的频率比冒泡还高因为它在排序类题目里最能看出一个人的功力。同样是手写快排有的候选人只能写出最基础的递归版有的能写出三数取中优化、尾递归优化、甚至非递归版本这差距是很大的。我建议你至少能手写两种快排第一种是基础版选择第一个元素作为pivot从数组两端开始向中间扫描交换不符合条件的元素第二种是填坑法用pivot的位置作为一个坑不断填充。笔试时建议写第二种因为它代码更直观不容易出错。快排最容易踩的坑有两个。第一个是递归终止条件写错很多人写成if (left right)而不是if (left right)导致递归无法退出。第二个是pivot的选择如果数组本身就是有序的每次选第一个元素当pivot快排会退化到O(n^2)而且递归深度会达到n大数组下直接栈溢出。所以我在笔试时通常会先判断数组长度如果小于某个阈值就切换成插入排序这个优化思路可以写进注释里阅卷人看到会给加分。4. JVM与内存题目从outofmemoryerror到对象生命周期4.1 内存区域划分与常见报错的对应关系用友的笔试题里JVM占了相当权重毕竟企业级系统常年跑在JVM上频繁出现的性能问题跟内存强相关。热词里那个java: outofmemoryerror: insufficient memory也是当年很多人搜过的报错说明这块确实是笔试和实战的双重热点。先理清一个最基本的问题JVM内存区域分为线程共享和线程私有两大类。线程共享的是堆和方法区JDK 8之后元空间取代了持久代线程私有的是虚拟机栈、本地方法栈和程序计数器。笔试里常考的对应关系是堆内存不够会抛java.lang.OutOfMemoryError: Java heap space而栈深度不够会抛StackOverflowError。这两个报错经常有人搞混。outofmemoryerror: insufficient memory这个报错其实更多见于JVM启动阶段启动时-Xms设置过大而实际物理内存不足或者32位操作系统下进程地址空间只有4GB堆申请太多就会报这个。笔试如果出这个题你要能答出不是堆内存用完而是JVM从操作系统申请内存失败。这和Java heap space是有区别的前者是启动或扩容时申请内存失败后者是堆内对象太多放不下了。笔试还有一种考法给你一段代码问这段代码运行时哪部分内存会报OOM。比如无限循环往ArrayList里添加对象答案应该是堆内存OOM无限递归调用一个方法答案是栈内存StackOverflowError用String.intern()大量添加字符串JDK 7以上是堆内存OOM。这类题的答题套路是先判断对象分配在哪里再分析哪个区域会耗尽。4.2 垃圾回收算法和可达性分析题的答题框架垃圾回收相关题目几乎是JVM部分的重头戏。要答好这类题建议记住这个答题框架怎么判断对象可回收引用计数法缺点、可达性分析、怎么回收复制算法、标记清除、标记整理、什么时候回收Minor GC、Major GC、Full GC触发条件。把这三层说清楚GC题目基本能拿大半分数。我在这里特别想说说引用计数法为什么会被淘汰。引用计数法听起来很直观每个对象有个计数器被引用就加一引用失效就减一减到零就回收。但它解决不了循环引用的问题两个对象互相引用没有外部引用指向它们计数器永远不为零内存就泄漏了。而可达性分析用GC Roots往下搜索搜索不到的对象就标记为可回收天然避免了循环引用的问题。这个考点在笔试里容易以判断题形式出现问你引用计数法可以实现内存自动回收所以没有内存泄漏问题答案是错的。讲到GC还应该顺便准备一下分代收集理论。为什么新生代用复制算法、老年代用标记整理或标记清除因为新生代朝生夕灭的对象多复制成本低老年代对象存活率高复制成本高所以用标记整理减少内存碎片。这些知识点之间是有逻辑关系的你按这个逻辑线去记忆比死记八股文要牢固得多。笔试里的简答题如果考到GC能把这个逻辑线清楚写出来就已经超过大多数人了。5. 多线程与并发题synchronized、volatile与线程池5.1 线程安全问题的识别与修复多线程编程是Java笔试里的一个分水岭。基础题往往考进程和线程的区别创建线程的几种方式进阶题考synchronized和lock的区别volatile能否保证原子性再往上就考线程池参数怎么设置。用友的笔试通常介于基础和进阶之间。先考你一道经典的volatile关键字能保证原子性吗正确答案是不能volatile只能保证可见性和有序性不能替代synchronized来保证原子性。但为什么很多人会记混呢因为volatile确实可以解决某些并发问题比如DCL单例模式中instance字段需要加volatile它的作用是禁止指令重排序防止拿到未初始化完整的对象。这是一个典型的、把volatile的适用场景说明白的例子。再考一个i在并发环境下是线程安全的吗不是。因为i在字节码层面对应了多条指令读取i、加一、写回i。当多个线程同时执行时会丢失中间加法的结果最终值小于预期。笔试里如果出代码题让你用多线程并发对一个共享变量执行i一万次问最终结果是多少答案是不确定大概率小于一万。这道题考察的是对复合操作非原子性的理解正确答案思路是给出解决方案用AtomicInteger的incrementAndGet、或者用synchronized修饰方法、或者用LongAdder做高并发场景的累加。5.2 线程池参数设计的实战考量线程池是另一个高频考点而且特别适合企业级软件开发场景。用友这种公司内部系统多很多业务场景是定时报表、批量对账、数据导入导出这些全是线程池的典型场景。笔试题目可能问ThreadPoolExecutor有哪些核心参数或者给你一个场景让你设计线程池。七个核心参数我来梳理一下corePoolSize核心线程数、maximumPoolSize最大线程数、keepAliveTime非核心线程存活时间、unit时间单位、workQueue任务队列、threadFactory线程工厂、handler拒绝策略。面试官经常追问的是当提交任务时线程池的执行顺序是什么。很多人答错的地方在这里。正确的顺序是当线程数小于核心线程数时每来一个任务直接创建一个新线程执行当线程数达到核心线程数时新任务会进入任务队列排队而不是继续创建新线程当任务队列满了才会创建非核心线程来执行任务当线程数达到最大线程数且队列也满了才会触发拒绝策略。这个顺序背下来很容易但理解背后的设计思想更重要线程池的目的不是一味地加线程而是通过队列做缓冲避免线程频繁创建销毁的开销同时也保护系统不被打垮。拒绝策略有四种AbortPolicy直接抛异常、CallerRunsPolicy调用者执行、DiscardPolicy直接丢弃、DiscardOldestPolicy丢弃最老的任务。实际项目里建议选CallerRunsPolicy或者自定义策略因为直接抛异常会中断业务流程静默丢弃数据又可能导致对账不平。如果你在笔试里能答到这层说明你真的考虑过生产环境的问题。6. 数据库、框架与设计模式非主考但必考的配角6.1 SQL优化与索引失效的场景题用友笔试的编程题里经常带一道SQL题这不是Java知识的范畴但企业级开发离不开数据库所以必须会用SQL处理业务场景。热词里那个用友u8发票结算错了虽然说的是产品操作问题但也侧面说明了一个点财务软件对数据准确性的要求极高SQL能不能精准地查出、修数据是基本功。SQL相关的常考题有这么几类三表联查的写法、聚合函数加GROUP BY的用法、索引失效的条件分析、慢查询的优化思路。这里我重点说索引失效因为这是最容易掉坑的选择题考点。常见的索引失效场景包括对索引列使用函数或计算如WHERE YEAR(create_time) 2024在索引列上进行隐式类型转换如字符串字段没有加引号模糊查询时通配符在关键词前面如LIKE %abc使用OR连接非索引列联合索引没有遵守最左前缀原则。这些场景不仅笔试考面试也爱问。要答好这类题建议理解一个基本原理索引的作用是快速定位数据任何导致无法直接比较索引列原始值的操作都会让优化器放弃索引扫描而改为全表扫描。6.2 Spring IoC/AOP与设计模式在笔试题中的表现用友的老系统很多是SSH或SSM框架后来逐渐转向Spring Boot。笔试涉及框架知识时考的不是某个注解怎么用而是核心思想。比如控制反转IoC解决了什么问题面向切面编程AOP适合做什么事情。IoC这个术语看着唬人其实可以用一个比喻来理解以前你买东西得自己跑菜市场自己new对象有了IoC容器之后你在APP上下单菜品就直接送到家容器帮你创建好对象并注入依赖。它解决的是对象创建和依赖管理的耦合问题让核心业务代码不关注对象的生命周期。AOP适合做日志、事务、权限这类横切关注点它的底层是动态代理。笔试里如果问Spring AOP和AspectJ有什么区别可以从实现方式切入Spring AOP基于动态代理运行时生成代理类只支持方法级别的切面AspectJ是编译时或类加载时织入支持字段、构造器、方法等多种切点性能更高但使用复杂度也高。这个区分能答出来说明你真的了解框架底层而不只是会用注解。设计模式在笔试中出现的频率也比较高其中单例模式是必须能默写出来的。为什么单例模式重要因为它在JDK和Spring里到处都是Runtime类、Spring的bean默认单例、数据库连接池、线程池。手写单例模式的时候建议写双重检查锁版本并且不要忘记volatile关键字。我见过太多候选人写DCL单例时漏了volatile问他为什么他说不出来。这个volatile是防止指令重排序导致拿到半初始化的对象属于实战中真正遇到的问题笔试里写出来是明显加分项。7. 笔试作答的节奏控制与复盘方法7.1 时间分配策略聊完了知识点最后说说考试技巧。一套Java笔试题选择题、简答题、编程题三部分时间通常在一到两个小时。我建议的时间分配比例是选择题不超过总时长的30%简答题不超过20%留至少一半时间给编程题。为什么编程题要留这么多时间因为编程题不仅要写出来还要保证代码能编译通过、逻辑正确。很多同学选择题纠结太久最后编程题只剩十几分钟匆匆写个半成品这部分分数拿不到笔试整体成绩就很尴尬。编程题答题时先把思路用注释写出来再补代码主体最后再检查边界条件。这个习惯看起来简单但能在紧张环境下减少大量低级错误。选择题要遵守不纠结原则一道题超过一分钟还没把握先凭第一感觉选一个标记一下全部做完再回来看。因为选择答题系统经常有倒计时而且反复纠结会消耗精力影响后续简答题的发挥。用友笔试的选项很多是以下说法正确的是这种多选变体建议把每个选项都当作判断题来看逐个分析对错而不是整体看哪个选项顺眼。7.2 如何把不会的题变成会做的题——复盘技巧笔试结束并不代表这件事就完了。我自己当年参加秋招时养成的一个习惯是每考完一场试马上在手机备忘录里记下不会的题目当天晚上回去逐一查资料弄明白。这套方法帮我避开了很多重复踩坑。这里分享一个复盘的优先级排序第一批复盘的是自己看懂了答案但仍不知道为什么当初没想到的题这说明思维方向有问题最值得深挖第二批是猜对了但心里没底的题说明知识点本身有缺口需要重新翻书巩固第三批是纯没见过的题目类型记录下来扩充知识地图。按这个优先级来复盘的效率会高很多。另外我建议给自己做一个错题知识树。比如一道HashMap的题做错了就往下追问HashMap的扩容机制、为什么阈值是0.75、红黑树化条件、JDK8和JDK7的区别、并发环境下的问题。每道错题至少延伸出三到五个关联知识点这样一套卷子做完可复习的框架就搭起来了。用友这种传统企业的笔试考得很广用知识树方式巩固一次复习相当于三次效果很好。归根结底笔试只是进入这个行业的第一步。我见过一些同学花大量时间刷各类题库但问到底层原理还是说不清这种背题式备考在面试环节很容易露馅。用友这类公司虽然笔试偏基础但面试官同样会往深问你写在笔试卷上的任何一个我会都有可能成为追问的起点。所以最好的准备方式还是老老实实把基础过一遍源码该看看、原理该想想笔试分数和面试表现都会自然跟着上去。希望这篇拆解能帮你理清复习方向祝秋招顺利。