news 2026/10/21 15:53:38

Java基础知识笔试题深度解析:集合、泛型、异常与避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java基础知识笔试题深度解析:集合、泛型、异常与避坑

简介:这是一份 Java 基础知识笔试题及答案文档,面向 Java 入门学习者、求职笔试备考者以及希望巩固语法基础的开发者,适合用来检验对基本概念、数据类型、运算符、控制结构、函数、数组、集合框架、泛型和封装等内容的掌握情况。资源中的题目既有选择题,也有程序阅读题和编程题,每道题均附参考答案或参考代码;内容涉及 String 字符串比较与替换、Calendar 日期计算、LinkedList 模拟堆栈、任意两个日期之间间隔天数统计等经典练习,可以帮助读者理解常见考点和易错点。资源包共 1 个 docx 文件,整体约 25KB,轻量易用,便于直接阅读、检索或打印复习。目前已有 1304 人学习下载。通过这份资料,读者可以系统梳理 Java 基础知识,快速定位薄弱环节,并结合实例代码提升程序设计与调试能力。

1. Java基础知识笔试题:这套资源到底能帮你解决什么

拿到这份Java基础知识笔试题及答案时,我的第一反应是"又是题海"。但当我把22道基础题和12道异常相关题全部跑了一遍,发现它本质是一套按知识点切片的自测工具:集合框架、包装类、泛型、Calendar日期计算、异常机制五大块全覆盖,每道题都有答案或参考代码。对准备笔试的新手,它是可以直接背诵的题库;对带新人的熟手,它是现成的面试提问清单。这套题最好的用法不是从头做到尾,而是把它拆开,按考点逐个验证自己的理解深度。接下来我从出题逻辑、代码实现、常见踩坑三个维度拆给你看。

2. 集合与包装类:从选择题答案看面试出题逻辑

2.1 高频选择题:这些考点为什么反复出现

先看三道典型选择题,它们分别对应包装类、相等比较和集合选型:

  • 第1题问包装原始字符串类型的类,答案是 String。注意这里的"包装类"是广义说法,严格说String是引用类型而非包装类,但笔试常这么叫。
  • 第2题问 java.lang 包中比较两个对象是否相等的方法,答案是 equals()。这里考察的是 == 和 equals 的语义差异,String 类重写了 equals,而 Object 默认实现仍然是引用比较。
  • 第4题问哪个集合不可以存储重复元素,答案是 Map。注意 Set 也不允许重复,但 Map 存储的是键值对,键不可重复,值可以重复。出题人故意把 Set 放在选项里就是让你区分"元素"和"键值对"两个概念。

这三道题放在一起看,出题逻辑很清晰:不是考你某个API怎么拼写,而是考你是否理解Java集合和对象的底层语义。第5题更典型,问 Map 和 List 的关系,答案是 D(Map 的 value 可以是 List 或 Map),这直接考察了集合嵌套的组合能力。实际开发中 JSON 反序列化、树形结构组装都会用到这种嵌套关系,所以面试官爱问。

2.2 LinkedList插入异常:add方法索引边界

第6题是这份资源里最容易翻车的代码题,原题如下:

import java.util.*; public class Test { public static void main(String[] args) { LinkedList list = new LinkedList(); list.add("A"); list.add(2, "B"); String s = (String) list.get(1); System.out.println(s); } }

答案是 B:运行时引发异常。原因在于 LinkedList 底层是双向链表,add(index, element)方法要求索引必须等于当前链表长度或小于长度。链表只有一个元素时,索引范围只能是 0 或 1,传 2 直接越界。我一般会这样给新人解释:LinkedList 不像 ArrayList 有连续内存可以"预留"位置,它必须通过遍历找到插入点,索引 2 对应的节点根本不存在,所以抛出 IndexOutOfBoundsException。

这里有个区分点:add("A")是尾插,等价于add(size(), "A");add(2, "B")是任意位置插入,需要节点存在。如果改成list.add(1, "B")就能输出 B。这个边界条件是笔试和面试的常客,记住"索引可等于长度,不可大于长度"就够了。

2.3 String.valueOf 三个重载版本:输出结果为什么是 10.0、true、bcd

第7题要求写出输出结果,代码如下:

char[] data = {'a', 'b', 'c', 'd'}; System.out.println(String.valueOf(10D)); System.out.println(String.valueOf(3 > 2)); System.out.println(String.valueOf(data, 1, 3));

输出结果是:

10.0 true bcd

第一个valueOf(10D)传入 double 类型,重载匹配到valueOf(double),返回 "10.0";第二个传入布尔表达式结果,匹配valueOf(boolean);第三个是坑点,valueOf(char[] data, int offset, int count)的第二个参数是起始偏移量,第三个参数是长度,所以从索引 1 开始取 3 个字符,正好是 b、c、d。

我见过不少人把第三个参数理解成结束索引,以为输出是 "bc"。这里要记住:offset 是起始位置,count 是复制长度。另外 char[] 重载版本会返回 char 数组的内容本身,而valueOf(Object)对数组调用会返回类似[C@15db9742的地址字符串,这是另一个高频易错点。

3. 泛型实战:从基础概念到能跑的泛型方法

3.1 泛型List与普通List:类型安全的代价与收益

第10题的参考答案把泛型的优点说得很清楚:类型安全、消除强制类型转换、提高代码重用率。我补一个实际对比场景:

// 普通 List:存入时随意,取出时强转容易出错 List list = new ArrayList(); list.add("hello"); Object obj = list.get(0); String str = (String) obj; // 泛型 List:编译期就限制类型,取出直接赋值 List<String> strList = new ArrayList<String>(); strList.add("hello"); String str2 = strList.get(0);

普通 List 存的是 Object,取出来需要强转。如果某处不小心add(123),运行时强转才会抛 ClassCastException,问题定位要翻整个调用链。泛型 List 在编译期就把这个风险拦住了。我通常会建议新人:集合声明一律带泛型,哪怕写List<String>比List多几个字符,省的是半夜排查类型异常的精力。

3.2 泛型方法minmax:T extends Comparable的边界处理

第19题要求写一个泛型方法,返回 int 数组和 String 数组的最大最小值。参考代码里有几个关键设计值得细看:

class ArrayAlg { public static <T extends Comparable> Pair<T> minmax(T[] a) { if (a == null || a.length == 0) { return null; } T min = a[0]; T max = a[0]; for (int i = 1; i < a.length; i++) { if (min.compareTo(a[i]) > 0) min = a[i]; if (max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<T>(min, max); } }

<T extends Comparable>是这段代码的核心约束,它告诉编译器:T 类型必须实现了 Comparable 接口,这样才能调用compareTo。如果不加这个边界,编译器会直接报错,因为 Object 没有 compareTo 方法。这里有两个改进点我可以补充:

  • 泛型边界建议写成<T extends Comparable<? super T>>,这是 Java 泛型规范里的经典写法,能支持父类实现了 Comparable 而子类没实现的情况。
  • 数组为空时返回 null,调用方需要做判空,否则会 NullPointerException。

测试部分用了Integer[]而不是int[],因为泛型只能匹配引用类型,基本类型 int 不满足T extends Comparable的约束。这一点新人很容易踩坑,写int[]进去编译直接失败。

3.3 泛型Map实现英文翻译:类型参数贯穿存取

第22题用泛型 Map 实现英文单词翻译,代码很短但把泛型 Map 的完整用法串起来了:

String[] eng = {"Apple", "Orange", "Green"}; String[] chs = {"苹果", "桔子", "绿色"}; Map<String, String> map = new HashMap<String, String>(); for (int i = 0; i < eng.length; i++) { map.put(eng[i], chs[i]); } String test = "Orange"; System.out.println(test + "翻译:" + map.get(test));

Map<String, String>声明了两个类型参数,键和值都是 String。put时如果键已经存在会覆盖旧值,get不存在时返回 null 而不是抛异常。这题在实际开发里可以扩展成加载配置文件键值对、缓存字典表等场景。注意 HashMap 的遍历顺序不保证插入顺序,如果需要按插入顺序输出,可以改成LinkedHashMap,这是我在项目里的习惯做法。

4. 日期计算与字符串转换:Calendar和API的四个实操场景

4.1 计算10天后的日期:Calendar的add与get组合

第12题要求计算距当前时间10天后的日期,参考代码使用 Calendar:

import java.util.Calendar; public class Ex12 { public static void main(String[] args) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_YEAR, 10); String strDate = cal.get(Calendar.YEAR) + "年" + (cal.get(Calendar.MONTH) + 1) + "月" + cal.get(Calendar.DATE) + "日"; System.out.println("10天后的日期为:" + strDate); } }

Calendar.getInstance()获取当前时间的日历实例,add(Calendar.DAY_OF_YEAR, 10)在当前日期上增加10天。注意两个细节:MONTH从 0 开始,所以输出月份时必须加 1;DATE和DAY_OF_MONTH等价,都是当前月中的第几天。如果跨月或跨年,add方法会自动进位,这是它比手动计算日期安全的根本原因。

参考代码没有包含具体的时间输出,只输出了日期。如果你需要完整时间,把HOUR_OF_DAY、MINUTE、SECOND拼进去就行。

4.2 两个日期间隔天数:毫秒差值的整除结果

第14题计算任意两个日期之间的天数,核心逻辑是毫秒差除以一天的毫秒数:

Calendar c1 = Calendar.getInstance(); c1.set(2010, 7, 1); Calendar c2 = Calendar.getInstance(); long ca1 = c1.getTimeInMillis(); long ca2 = c2.getTimeInMillis(); long days = (ca2 - ca1) / (24 * 60 * 60 * 1000); System.out.println(days);

这里有个隐藏陷阱:c1.set(2010, 7, 1)设置的是 2010年8月1日,因为 MONTH 从 0 开始。如果意图是7月1日,应该写成set(2010, 6, 1)或set(2010, Calendar.JULY, 1)。另外整除运算会有精度丢失,比如间隔时间是25小时,整除后得到1天,实际上是2天。更严谨的做法是:

long days = (ca2 - ca1) / (24 * 60 * 60 * 1000L); if ((ca2 - ca1) % (24 * 60 * 60 * 1000) != 0) { days++; }

4.3 parseInt与valueOf:进制参数与返回类型差异

第16题考察字符串转数值的两个API:

String str1 = "200"; System.out.println(Integer.parseInt(str1, 16)); // 输出 512 String str2 = "123456"; System.out.println(Float.parseFloat(str2)); // 输出 123456.0

Integer.parseInt(String, int radix)的第二个参数是进制,所以 "200" 按十六进制解析,结果是 2*256=512。Float.parseFloat返回基本类型 float,而Float.valueOf返回包装类型 Float,两者底层解析逻辑一致,区别在使用场景:需要参与基本类型运算用parseFloat,需要放入集合用valueOf。第17题还有一个自定义的十进制转十六进制实现,那个方法循环中取余数再翻转字符串,逻辑对,但用Integer.toHexString(365)一行就能解决。笔试如果要求手写,可以写简单的递归或循环,不必硬记那个 switch 分支。

5. 异常机制与避坑:try-catch-finally的五个踩坑记录

5.1 Throwable体系与异常分类:父子关系必须记牢

第3题问所有异常的父类,答案是 Throwable。派生关系是:

Throwable ├── Error (内部错误,如硬盘损坏、内存溢出) └── Exception ├── RuntimeException (运行时异常,如除数为0、数组越界) └── 其他受检异常 (如文件不存在)

第4题问哪些操作不会抛出异常,答案是"以上都会",这题被坑过的人很多。int x = 1 / 0抛 ArithmeticException;负数索引访问数组抛 ArrayIndexOutOfBoundsException;打开不存在的文件抛 FileNotFoundException。三条都对应异常,所以选 D。第6题问多重 catch 中最后列出哪个类,答案是 Exception 放最后,因为子类异常必须排在父类前面,否则父类会先捕获,子类的 catch 块永远执行不到。

5.2 finally与return的优先级:为什么返回值是3

第9题是这套题里最有含金量的一道:

public int count() { try { return 5 / 0; } catch (Exception e) { return 2 * 3; } finally { return 3; } }

结果返回 3。原因:try 中 5/0 抛出异常,进入 catch 块,catch 准备返回 6,但 finally 在 return 之前强制执行,finally 中的 return 3 直接覆盖了 catch 的返回值。这是 Java 规范里一个反直觉的设计:finally 中的 return 会压制任何其他返回值,包括 try 和 catch 块中的异常抛出。我在代码评审里见过有人这样写,一条原则解决:不要在 finally 里写 return,finally 只做资源清理,如关闭流、释放锁。

第8题验证了另一个现象:try 中有 return 时 finally 仍然执行,所以输出 "try,finally" 而不是只输出 "try,"。

5.3 自定义异常与Scanner输入:异常处理机制的完整落点

第11题要求自定义异常并做输入校验:

class MyException extends Exception { private String errorMsg; public MyException(String errorMsg) { this.errorMsg = errorMsg; } @Override public String toString() { return errorMsg; } } public class Ex11 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); String strIn = scan.nextLine(); try { if (strIn.equals("abc")) { throw new MyException("输入的字符串不正确!"); } } catch (MyException e) { System.out.println(e); } } }

自定义异常类继承 Exception,重写 toString 可以自定义输出内容。注意这里scan.nextLine()读取的是整行输入,如果输入两端有空格,equals("abc")判断会不相等。稳妥做法是strIn.trim().equals("abc")或在读取后先trim()。第12题要求从键盘输入两个数做减法,输入非数字时程序不崩溃,核心思路是在 catch 块里提示用户重新输入,而不是直接退出,常见做法是用 while 循环包裹输入逻辑,直到输入合法为止。

5.4 避坑记录:五个实测踩坑

踩坑一:LinkedList add(2,"B") 运行时异常。 现象:代码编译通过,运行时报 IndexOutOfBoundsException。 原因:链表中只有一个元素,索引 2 对应的插入位置超出了链表长度约束。 解决:插入位置必须是 0 到 size() 之间的整数,改成add(1, "B")或add("B")。

踩坑二:Calendar 月份从 0 开始,set 出来日期不对。 现象:写c1.set(2010, 7, 1)期望 7 月 1 日,输出却是 8 月 1 日。 原因:Calendar.MONTH 的取值范围是 0-11,7 代表 August。 解决:使用常量Calendar.JULY,逻辑不会错也不会看走眼。

踩坑三:finally 里的 return 覆盖 catch 里的 return。 现象:count() 方法 catch 块返回 6,实际结果返回 3。 原因:finally 在 return 前执行,其 return 优先级最高。 解决:finally 只做清理,返回值统一放最后一行,或使用临时变量。

踩坑四:String.valueOf(char[], offset, count) 参数理解偏差。 现象:String.valueOf(data, 1, 3)有人以为取索引 1 到 3,实际输出 "bcd"。 原因:第二个参数是起始偏移量,第三个参数是长度。 解决:只需要记住 count 是复制的字符个数,不是结束下标。

踩坑五:泛型方法传入 Integer[],编译期强制约束。 现象:写<T extends Comparable>后传入 int[],编译直接报错。 原因:基本类型 int 不是对象,不满足泛型边界。 解决:使用包装类型Integer[],如果必须处理基本类型数组,单独重载非泛型方法。

6. 把题库变成面试清单:验证方法与背诵技巧

6.1 按知识点分组自测

这套题的正确打开方式不是从头做到尾,而是按知识点分组。我建议你把自己当成面试官,拿这份题反过来出问题。比如集合框架部分,看到"Map 和 List 的区别"这道题,向自己追问三个层次:

  • 第一层:Map 是键值对,List 是有序可重复集合,Set 不可重复。
  • 第二层:HashMap 的键为什么不可重复?因为它的底层是数组加链表或红黑树,靠 hashCode 和 equals 定位,两个键 hashCode 相同还要 equals 判断。
  • 第三层:如果自定义对象作为 HashMap 的键,不重写 hashCode 会怎样?会导两个内容相同的对象被当作不同键存入。

把每个选择题都这样扩展成三层追问,一套题库就能覆盖大部分面试场景。编码题也一样,第19题的泛型方法,我一般会追一个场景:泛型方法能不能放进一个非泛型类里?可以,泛型方法的方法级类型参数与类是否泛型无关,ArrayAlg 类就不是泛型类,但它内部定义了泛型方法 minmax。

6.2 代码题改造成编码题:一份可复现的自测清单

我整理了一份对照表,把第2章到第5章的核心代码题映射到能力项,你可以直接拿去自测:

题目编号核心考点自测方式容易翻车的点
第6题LinkedList 索引边界换 ArrayList 再跑一次对比不知道两者插入机制差异
第7题String.valueOf 重载把 double 改成 float,观察输出记混 char[] 参数语义
第12题Calendar 日期计算改成 -10 天,验证跨月进位忘记 MONTH 从 0 开始
第14题日期差值设置两个相隔1天的日期验证整除精度丢失
第19题泛型边界去掉 extends Comparable 看编译报错用 int[] 提交泛型方法
第11题自定义异常输入 "abc " 带空格再跑没做 trim 导致判断失效

这套自测跑一遍大约40分钟,但每道题都值得跑。第6题的运行时异常、第12题的月份偏移、第7题的重载匹配,都是我实际在编译器和线上日志里见过的真实问题。有些人觉得这些题是"背答案",但当你亲手把add(2, "B")这个越界索引跑出来,比看十遍答案都印象深刻。

另外一个高效技巧是改参数验证理解:第4题的 Calendar 日期计算,把DAY_OF_YEAR改成DAY_OF_MONTH和MONTH,观察三种情况下的进位区别;第16题的 parseInt 第二个参数换成 8 和 2,看同一字符串在不同进制下的解析结果。这种"改一行参数、看一次输出"的方法,比死记题目答案更能训练出对 API 边界的敏感度。

从那以后,我每次带新人过 Java 基础,都会强制走一遍这套流程:先让他们把这 34 道题按知识点分组跑完,再要求每人挑三道题修改参数做扩展验证。整个过程不评价对错,只要求记录每个输出结果和自己的推测。这种把题库当实验手册的做法,比起直接对答案,学习效果要好得多。希望这套方法对你也有用。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 16:16:45

陶瓷基板全流程追溯体系:从原料到出货的批次管理实战

陶瓷基板做全流程追溯&#xff0c;这几年已经从行业里的"加分项"变成了客户审核的"及格线"。我做某车规陶瓷基板项目时&#xff0c;客户现场审核第一件事就是抽两个出货批次&#xff0c;要求在半小时内把粉料供应商、烧结炉曲线、镀层厚度、出货去向全部调…

作者头像 李华
网站建设 2026/10/18 10:59:53

零基础小白网安自学指南:4 个月吃透网安,可上手 SRC 漏洞挖掘

零基础小白网安自学指南&#xff1a;4 个月吃透网安&#xff0c;可上手 SRC 漏洞挖掘 温馨提示&#xff1a;网络安全技术仅用于授权环境学习测试&#xff0c;未经授权的渗透攻击属于违法行为&#xff0c;请遵守《网络安全法》。 一、基础阶段&#xff5c;1.5 个月&#xff08;6…

作者头像 李华
网站建设 2026/10/20 21:09:58

本地部署OpenClaw(原Clawdbot)环境变量配置:Windows/macOS/Linux全攻略

好的&#xff0c;我看到您的请求了。针对“本地部署OpenClaw&#xff08;原Clawdbot&#xff09;时&#xff0c;不同操作系统下配置环境变量的具体方法”这个项目标题&#xff0c;我将直接输出一篇高质量的中文技术博文。请直接阅读以下内容。1. 项目概述&#xff1a;为什么环境…

作者头像 李华
网站建设 2026/10/20 23:44:43

Windsurf AI IDE 从安装到实战:核心功能与高效使用指南

第一次打开 Windsurf AI IDE 的时候&#xff0c;我其实没抱太大期望。这几年 AI 编辑器没少折腾&#xff0c;很多都是“补全很惊艳&#xff0c;一改真实代码就翻车”的噱头。但把几个正经项目丢进去跑完之后&#xff0c;我的判断变了&#xff1a;Windsurf 不是换皮玩具&#xf…

作者头像 李华
网站建设 2026/10/18 1:14:07

混沌保密通信工程实践:从混沌同步到安全评估的完整链路

简介&#xff1a;一份关于混沌保密通信应用的毕业论文&#xff0c;面向信息安全与通信工程领域研究者、研究生及高年级本科生&#xff0c;系统梳理混沌理论在保密通信中的原理与实现路径&#xff0c;并以Chua电路为主线展开同步技术研究。整份资源为1个doc文档&#xff0c;包体…

作者头像 李华
网站建设 2026/10/18 10:24:13

运维实习第一阶段练什么?基础认知、操作规范与排查意识

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华