简介:这份资源面向 Java 初学者与准备笔试的求职者,系统梳理 Java 基础知识笔试题及参考答案,帮助读者在刷题中巩固语法概念、查漏补缺。内容覆盖基本概念、八种基本数据类型与引用类型、运算符、顺序/选择/循环三类控制结构、函数、数组、集合框架、泛型与封装等模块,题目形式包含选择题、代码运行结果分析与编程题,如字符串比较与替换、Calendar 计算日期、自定义 Stack 堆栈实现等,均附参考代码与解析。资源包共 1 个 docx 文件,约 25KB,体积轻便,便于打印或本地查阅。目前已有 1307 人学习下载,适合作为课程复习、面试前自测与课堂练习的配套题库使用,读者可据此逐章检验掌握程度,理解常见考点与易错细节,提升 Java 程序设计与开发能力。
1. Java 基础笔试题的知识地图:从语法骨架到集合与泛型
Java 基础笔试题看起来零散,实际有一条很清晰的主线:语法层 → 对象层 → 容器层 → 抽象层。语法层考数据类型、运算符、控制结构;对象层考封装、继承、多态、String 与包装类;容器层考数组、List、Set、Map 的选型与行为差异;抽象层考泛型、异常机制、自定义类型设计。很多人复习时按题号顺序刷,刷完还是记不住,原因就是没有把题目挂到这张地图上。这份资源把选择、填空、编程三类题型混编在一起,恰好覆盖了从概念辨析到代码落地的完整链路。适合已经学过一遍 Java、正在准备笔试或期末复习的人,用来做一次系统性的查漏补缺,而不是从零起步的入门材料。
2. 语法与对象基础:包装类、String 与封装的三条主线
2.1 包装类与 String 的对应关系
笔试里第一类高频题就是「什么类型对应什么包装类」。原始字符串类型对应的包装类是String,而八种基本数据类型各有自己的包装类。这里最容易混的是char对应Character,int对应Integer,其余都是首字母大写。梳理下来会发现,包装类的考点集中在三处:类型对应、自动装箱拆箱、以及valueOf与parseXxx的区别。
| 基本类型 | 包装类 | 常见转换方法 |
|---|---|---|
| byte | Byte | Byte.valueOf / Byte.parseByte |
| short | Short | Short.valueOf / Short.parseShort |
| int | Integer | Integer.valueOf / Integer.parseInt |
| long | Long | Long.valueOf / Long.parseLong |
| float | Float | Float.valueOf / Float.parseFloat |
| double | Double | Double.valueOf / Double.parseDouble |
| char | Character | Character.valueOf |
| boolean | Boolean | Boolean.valueOf / Boolean.parseBoolean |
parseInt和valueOf的差别是选择题常客:parseInt返回基本类型int,valueOf返回包装类对象。资源里有一道题要求把字符串"200"按十六进制转成十进制,用的就是Integer.parseInt(str, 16),第二个参数是进制基数,不写默认按十进制解析。另一道题把long转字符串用String.valueOf(num),把十进制转十六进制则手写了一个除基取余的转换函数,这类题考的是「有没有现成 API」和「会不会手写算法」两条路。
2.2 String 比较:== 与 equals 的分水岭
字符串比较是笔试翻车率最高的点之一。==比较的是引用地址,equals比较的是内容。资源里的示例用str1 = "It is"和str2 = "It is"做对比,两个字面量指向常量池同一对象,所以==也可能为 true,但这属于字面量的特殊情况,不能当成通用结论。真正要记住的是:判断内容一律用 equals,判断是否为同一对象才用 ==。
字符串拼接与替换也是常考点。concat返回新字符串,原对象不变;replace(char, char)做字符级替换。资源示例把"It is"与"a book"连接后再把i替换成m,输出结果需要按「先拼接、后替换」的顺序推。这里有个容易忽略的细节:String是不可变类,所有「修改」操作都产生新对象,原变量不变,所以链式调用时要注意接收返回值。
2.3 封装的含义与封装类的边界
封装的标准答案是「把数据项和方法隐藏在对象内部,隐藏方法实现」。但笔试常把它和「封装类」混在一起问。封装是面向对象的设计原则,封装类是包装类的另一种叫法,指Double、Integer、Float、Byte、Long、Character、Short、Boolean这八个类。答题时要把两个概念分开写:封装讲的是访问控制与信息隐藏,封装类讲的是基本类型的对象化。资源里这道题同时问了两件事,很多人只答一半就丢分。
提示:封装类列表要背全八个,少写一个
Character或Boolean就是常见失分点。
3. 数组与集合框架:List、Set、Map 的选型与行为差异
3.1 数组的默认值与越界
数组题考两个方向:默认初始化和下标越界。new int[5]里每个元素默认是0,new Object[5]默认是null,这是 JVM 给成员变量的零值规则。资源里有一段代码先打印i[4]再调用方法打印局部数组K[3],输出是0 0 null,顺序不能乱。另一道题用arr[2]访问长度为 2 的数组,必然抛ArrayIndexOutOfBoundsException,捕获后打印堆栈即可。
数组和集合的第一个分界点是长度:数组定长,集合可变。第二个分界点是存储类型:数组可以存基本类型,集合只能存对象(泛型后由编译器保证类型)。第三个分界点是 API 丰富度:集合有add、remove、contains等现成方法,数组只能靠Arrays工具类。
3.2 List、Set、Map 的存储规则
集合选型题的核心就一句话:List 有序可重复,Set 无序不可重复,Map 键值对且键不可重复。资源里有一道题问「哪个集合不可以存储重复元素」,选项里Set和Map都符合「不可重复」的描述,但标准答案给的是Map,因为Map存的是键值对,键唯一;而Set在部分教材语境下被归为Collection子接口,题目问的是「集合中」的泛指。这类题要结合选项语境判断,不能死记。
另一道题问 Map 和 List 的关系,正确说法是「Map 的 value 可以是 List 或 Map」。Map不继承List,两者是并列的集合体系;List里可以放Map或List,因为元素类型是Object;集合也不限于数据库数据。这道题的价值在于帮你理清集合框架的继承树:Collection下分List和Set,Map独立成体系。
3.3 LinkedList 的插入陷阱
资源里有一道经典运行结果题:LinkedList先add("A"),再add(2, "B"),然后get(1)。很多人以为会输出B,实际运行抛异常。原因是add(int index, E element)要求索引不超过当前大小,此时列表只有 1 个元素,合法索引是 0 或 1,传 2 就越界,运行时抛IndexOutOfBoundsException。这道题考的是「编译通过不等于运行通过」,LinkedList的索引插入必须先检查边界。
LinkedList<String> list = new LinkedList<>(); list.add("A"); // 此时 size=1,合法插入位置是 0 或 1 list.add(1, "B"); // 正确:在末尾插入 // list.add(2, "B"); // 错误:索引越界,运行时抛异常 String s = list.get(1); // 输出 B参数说明:add(index, element)的index取值范围是0到size(),等于size()时等价于追加。get(index)的合法范围是0到size()-1。判断这类题时,先数当前元素个数,再对照索引上限,基本不会错。
3.4 用集合实现栈与通讯录
资源里有两个综合编程题值得单独拎出来。第一个用LinkedList实现后进先出的栈:addFirst入栈、getFirst取栈顶、removeFirst出栈,三个方法都作用在链表头部,天然满足 LIFO。第二个用List<Student>存通讯录,Student类封装姓名和电话并重写toString,遍历输出。这两题考的是「选对容器 + 封装数据」的组合能力,也是笔试编程题的常见套路。
class Stack { private LinkedList<Object> list = new LinkedList<>(); public void add(Object obj) { list.addFirst(obj); } // 入栈 public Object get() { return list.getFirst(); } // 取栈顶 public void delete() { list.removeFirst(); } // 出栈 }逻辑说明:所有操作集中在链表头部,addFirst和removeFirst的时间复杂度都是 O(1),比用ArrayList在尾部操作再反转更直接。参数Object表示可存任意类型,实际使用时可以加泛型约束。
4. 泛型与类型安全:从类型参数到泛型方法
4.1 泛型的三个优点
泛型的标准答案有三条:提高类型安全、消除强制类型转换、提高代码重用率。展开说,类型安全是指编译期就能发现类型不匹配,而不是运行期抛ClassCastException;消除强转是指List<String>取元素时不用再写(String);重用率是指同一套逻辑可以适配多种类型。泛型List和普通List的区别也在这里:泛型List<String>只能存字符串,普通List什么都能存,取出来要自己强转。
4.2 泛型方法与泛型类的写法
资源里有两个泛型编程题。第一个是泛型方法minmax,返回Pair<T>,要求T extends Comparable,这样内部才能调用compareTo比较大小。第二个是fromArrayToCollection,把数组元素批量加入集合,签名是static <T> void fromArrayToCollection(T[] a, Collection<T> c)。
class Pair<T> { private T min, max; public Pair(T min, T max) { this.min = min; this.max = max; } public T getMin() { return min; } public T getMax() { return max; } } class ArrayAlg { public static <T extends Comparable> Pair<T> minmax(T[] a) { if (a == null || a.length == 0) return null; T min = a[0], 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无法调用。Pair<T>是泛型类,两个字段类型由实例化时决定。测试时Integer[]和String[]都能传入,因为两者都实现了Comparable。这里最容易错的是漏写上界,编译直接报「找不到 compareTo 方法」。
4.3 泛型 Map 的实际用法
资源里用Map<String, String>做了英汉翻译,键是英文单词,值是中文含义,put存入、get取出。另一道题用HashMap存学生成绩,put同一个键会覆盖旧值,所以「李四」从 83 改成 100 只需再put一次。这两题合起来说明Map的两个核心行为:键唯一、重复put覆盖。泛型在这里的作用是限定键值类型,避免取出时强转。
注意:
HashMap的键重复判断依赖equals和hashCode,自定义对象作键时必须同时重写这两个方法,否则覆盖行为不符合预期。
5. 异常机制与日期处理:try-catch-finally 的执行顺序
5.1 异常的分类与父类
所有异常的父类是Throwable,它下面分Error和Exception两支。Error是致命错误,如硬件故障;Exception是程序可处理的异常,又分运行时异常(如除零、数组越界)和受检异常。资源里有一道题问「除数为零、负数索引访问数组、打开不存在的文件」哪个不抛异常,答案是都会抛,分别对应ArithmeticException、ArrayIndexOutOfBoundsException、FileNotFoundException。
多重 catch 的顺序也是必考点:子类异常在前,父类异常在后。Exception是大多数异常的父类,必须最后列出,否则前面的具体异常永远匹配不到,编译直接报错。
5.2 finally 与 return 的优先级
这是异常章节最容易翻车的地方。资源里有两道题:第一道try里return,finally里打印,输出是try,finally,因为finally在return之前执行;第二道count()方法try返回5/0抛异常,catch返回6,finally返回3,最终返回值是3。结论很硬:finally 里的 return 会覆盖 try 和 catch 里的 return。
public int count() { try { return 5 / 0; // 抛 ArithmeticException } catch (Exception e) { return 2 * 3; // 本应返回 6 } finally { return 3; // 实际返回 3,覆盖前面的 return } }逻辑说明:finally块在方法返回前一定执行,如果其中也有return,会直接以它的值为准。实际开发中应避免在finally里写return,否则会吞掉异常和正常返回值,属于血泪经验级别的坑。
5.3 自定义异常与输入容错
资源里有两个自定义异常题。第一个定义MyException extends Exception,输入"abc"时throw出去并捕获打印;第二个从键盘读两个数做减法,输入含非数字时靠异常机制兜底。自定义异常的写法要点:继承Exception(受检)或RuntimeException(非受检),提供带参构造,重写toString或getMessage输出错误信息。
class MyException extends Exception { private String errorMsg; public MyException(String errorMsg) { this.errorMsg = errorMsg; } @Override public String toString() { return errorMsg; } }参数说明:errorMsg保存异常描述,toString决定打印内容。抛出时用throw new MyException("..."),捕获时catch (MyException e)后打印e即可。注意throw是抛语句,throws是方法声明,两个词只差一个 s,选择题经常拿来挖坑。
5.4 Calendar 的月份偏移与日期计算
Calendar有两个高频坑。第一,获取实例用getInstance(),不是new Calendar(),因为它是抽象类。第二,get(Calendar.MONTH)返回 0 到 11,一月是 0,所以输出月份要加 1。资源里计算 10 天后日期的示例就写了cal.get(Calendar.MONTH) + 1,漏加 1 就是经典错误。
日期间隔计算用毫秒差:两个Calendar取getTimeInMillis()相减,再除以24 * 60 * 60 * 1000得到天数。这里要注意整数除法会截断,跨时区或夏令时场景下毫秒差不一定精确等于自然日,笔试一般按理想情况算。
Calendar c1 = Calendar.getInstance(); c1.set(2010, 7, 1); // 注意:7 表示八月,月份从 0 开始 Calendar c2 = Calendar.getInstance(); long days = (c2.getTimeInMillis() - c1.getTimeInMillis()) / (24 * 60 * 60 * 1000);参数说明:set(year, month, date)的month是 0 基,写 7 实际是八月,这是最容易错的地方。getTimeInMillis返回自纪元以来的毫秒数,相减后除以一天的毫秒数得到间隔天数。
6. 易错点清单:五类最容易翻车的笔试题
6.1 易错点一:== 与 equals 混用
为什么漏:字面量字符串在常量池中复用,==偶尔为 true,让人误以为==能比较内容。怎么补:记住「内容用 equals,地址用 ==」,遇到字符串比较先看是不是字面量,再看题目问的是内容还是引用。
6.2 易错点二:集合索引越界
为什么漏:add(index, element)编译期不检查索引,运行时才抛异常,刷题时容易凭直觉选「输出 B」。怎么补:做LinkedList、ArrayList索引题时先数size(),合法插入位置是0到size(),取值是0到size()-1。
6.3 易错点三:finally 覆盖返回值
为什么漏:直觉认为catch里的return先执行,忽略了finally一定在返回前运行。怎么补:看到try-catch-finally里有多个return,直接以finally的返回值为准,并记住这是应避免的写法。
6.4 易错点四:Calendar 月份从 0 开始
为什么漏:set(2010, 7, 1)看起来像七月,实际是八月;get(MONTH)不加 1 就少一个月。怎么补:所有Calendar月份操作统一「读加一、写减一」,形成肌肉记忆。
6.5 易错点五:泛型漏写上界
为什么漏:泛型方法里直接调compareTo,忘了T没约束就没有这个方法。怎么补:只要方法体用到Comparable的方法,签名必须写<T extends Comparable>,编译报错时先查上界。
7. 复习落地:一份可执行的查漏补缺清单
复习到这一步,重点不是再刷一遍题,而是把错题按模块归位。我的做法是准备一张四列的表:模块、题目编号、错因、补法。模块按「语法与对象 / 数组与集合 / 泛型 / 异常与日期」四类分,错因只写一句话,补法写具体动作,比如「重写一遍 LinkedList 插入边界」「手推 finally 返回值」。
| 模块 | 必查点 | 自检动作 |
|---|---|---|
| 语法与对象 | 八个包装类、== 与 equals、String 不可变 | 默写包装类表,手推一道字符串比较题 |
| 数组与集合 | 默认值、越界、List/Set/Map 选型 | 画集合继承树,标出可重复与有序性 |
| 泛型 | 类型参数、上界、泛型方法签名 | 手写 minmax,检查是否写上界 |
| 异常与日期 | Throwable 体系、finally 顺序、月份偏移 | 手推两道 return 题,写一次日期加十天 |
具体执行分三步。第一步,把资源里的选择题全部过一遍,只标错题不抄答案,错题按上表归模块。第二步,编程题不看书手写一遍,重点写Stack、minmax、Calendar加十天这三个,写完对照参考代码找差异,差异点就是薄弱点。第三步,考前只翻错题表和上表,不再看新题。
// 自检模板:把每个错题写成可运行的最小用例 public class Check { public static void main(String[] args) { // 例:验证 finally 覆盖 System.out.println(count()); // 预期 3 // 例:验证 LinkedList 边界 java.util.LinkedList<String> l = new java.util.LinkedList<>(); l.add("A"); l.add(1, "B"); // 合法 System.out.println(l.get(1)); // 预期 B } static int count() { try { return 5 / 0; } catch (Exception e) { return 6; } finally { return 3; } } }这段模板的价值在于把「看题」变成「跑题」,每个错点都能用几行代码复现,跑一遍比背十遍答案都牢。参数不用改,直接替换方法体即可。
从那以后我每次复习 Java 基础,都强制先画知识地图再刷题,错题必须归到四个模块之一,归不进去就说明地图有缺口。希望这份梳理帮到你,少走几道本来会翻车的弯路。
本文还有配套的精品资源,点击获取