☰
Java笔试高频陷阱:包装类、equals、Calendar偏移与finally劫持
2026/10/24 12:23:27 网站建设 项目流程

简介:本资源是一份面向Java初学者与求职者的系统性笔试复习资料,聚焦Java核心基础知识点的考查与巩固。内容覆盖Java基本概念、数据类型、运算符、控制结构、方法定义、数组操作、集合框架(List/Set/Map)、泛型机制、封装原理及常见API应用等高频考点,题型包括单选、多选、判断、简答与编程实践,每道题均附标准答案与关键解析,如String包装类辨析、equals()方法作用、Calendar实例获取、Set去重特性、泛型安全优势等,助力读者精准查漏补缺。资源为1个25KB的Word文档(.docx),排版清晰、题目编号规范、参考答案紧随其后,便于打印或离线刷题。目前已有1307人学习下载,适合校招准备、课程期末复习及Java入门能力自测。

1. Java笔试真题不是考“会不会写”,而是考“有没有踩过坑”

你翻过几十道Java基础题,却在面试现场被问“String.valueOf(null)返回什么”当场卡壳;你背熟了ArrayList和LinkedList区别,但看到list.add(2, "B")就下意识选C——结果这题根本没考集合结构,考的是索引越界时的运行时行为。这不是知识盲区,是典型“纸面会、实操翻车”的信号。这份《Java基础知识笔试题及答案》覆盖近3年高频考点:包装类命名陷阱、equals()与==的语义分水岭、Calendar日期计算的月份偏移玄学、泛型擦除后类型安全的假象、异常传播中finally对return的强制劫持。全卷22道题+12道异常专项题,每道都来自真实笔试现场——不是教科书例题,是HR筛简历时真正划线的生死线。适合正在突击校招/社招笔试的开发者:不求你写出Spring源码,但必须让面试官相信,你写的每一行if、每一个get(),都清楚背后藏着多少个NullPointerException在等你。


2. 高频考点:包装类、字符串比较、集合特性与Calendar实例化

2.1 包装类命名规则:为什么String是特例?

题目1直击要害:“Java中提供了名为()的包装类来包装原始字符串类型”。选项A-C全是数值型包装类(Integer/Char/Double),D是String。很多考生秒选D,却答不出为什么String不是StringWrapper或Str。关键点在于:String不是原始类型的包装类——Java只有8种原始类型(byte/short/int/long/float/double/char/boolean),String是引用类型,其本质是char[]数组的不可变封装。所谓“包装原始字符串类型”是命题人故意设的语义陷阱,实际考察你是否混淆了“字符串字面量”和“原始类型”的概念。String类存在,是因为它需要提供substring()、replace()等不可变操作,而非为char提供包装(Character才是char的包装类)。

提示:所有包装类名都严格对应原始类型名首字母大写(int→Integer,char→Character),唯独String无原始类型对应,它是独立设计的不可变引用类型。

2.2equals()vs==:从题目2到题目11的连环套

题目2问java.lang包中哪个方法比较对象相等,答案是equals()。但题目11立刻升级难度:测试str1="It is"和str2="It is"是否相等,代码中同时出现str1==str2和str1.equals(str2)。这里埋着三重雷:

  • 第一重:字符串字面量在常量池中复用,str1==str2返回true(地址相同);
  • 第二重:若用new String("It is")创建str2,则==返回false,equals()仍为true(内容相同);
  • 第三重:题目11的参考代码输出str1==str2的结果:true,但这是仅限于字面量场景的巧合,绝不能当成==可替代equals()的依据。

面试官常追问:“如果str1是从数据库查出的字符串,str2是用户输入的,还能用==吗?”——答案必须斩钉截铁:永远用equals(),且先判空(str1 != null && str1.equals(str2)),否则NullPointerException直接挂掉。

2.3 集合去重机制:题目4和题目5的底层逻辑

题目4问“哪个集合不可以存储重复元素”,选项A是Set,C是Map。正确答案是A,但很多人错选C。误区在于:Map的key确实不能重复,但value可以重复,而题目问的是“集合”能否存储重复元素——Map本身不属于Collection接口体系(它实现的是Map接口),Set才是专门设计为无序、不可重复的集合。题目5进一步验证:Map的value可以是List或Map(D选项正确),这说明Map的存储能力远超去重需求,它的核心约束只在key唯一性。

2.4Calendar.getInstance():日期操作的致命偏移

题目3考Calendar实例化方法,答案是getInstance()。但题目12的代码暴露真正考点:cal.set(2010, 7, 1)设置的是2010年8月1日(MONTH字段从0开始计数!)。题目14计算日期差时用c1.getTimeInMillis()转毫秒再除以86400000,看似正确,但忽略时区影响——Calendar.getInstance()默认使用系统时区,若两台机器时区不同,毫秒差可能偏差1天。生产环境必须显式指定时区:Calendar.getInstance(TimeZone.getTimeZone("GMT+8"))。


3. 易错题:90%考生栽在这5个“反直觉”陷阱

3.1 LinkedList索引越界:题目6的运行时炸弹

错在哪:看到list.add(2, "B"),下意识认为LinkedList支持随机插入,选C(输出A)或D(输出B)。
为什么错:LinkedList的add(int index, E element)方法要求index必须在[0, size]范围内(size是当前元素个数)。题目中list初始为空(size=0),add(2, "B")试图在索引2处插入,但合法索引只有0(头插)和1(尾插),2已越界。
怎么答对:LinkedList虽是链表,但add(index, e)会遍历查找位置,越界时抛出IndexOutOfBoundsException(继承自RuntimeException),属于运行时异常,编译通过但运行报错。答案B正确。

3.2String.valueOf()的null安全:题目7的隐藏考点

错在哪:看到String.valueOf(data,1,3),只关注字符数组截取,忽略前两行String.valueOf(10D)和String.valueOf(3>2)。
为什么错:String.valueOf(double d)返回"10.0"(注意小数点),String.valueOf(boolean b)返回"true"(全小写),而String.valueOf(char[] data, int offset, int count)当data为null时返回"null"字符串。但题目中data非空,所以输出"bcd"。易错点在于混淆valueOf的多个重载版本——它对null的处理因参数类型而异:对Object类型参数,valueOf(null)返回字符串"null";对基本类型参数,不会传入null(编译不通过)。

3.3 数组初始化默认值:题目8的“零值幻觉”

错在哪:看到int i[] = new int[5],知道i[4]是第5个元素,输出0;但对Object obj[] = new Object[5],误以为obj[2]也输出0。
为什么错:Java中基本类型数组元素默认初始化为零值(int为0,boolean为false),但引用类型数组元素默认初始化为null。obj[2]是null,System.out.println(null)直接输出null字符串,而非0。

3.4finally劫持return:题目9的控制流黑匣子

错在哪:看到try{return 5/0;},认为除零异常进入catch,执行return 2*3即6,选B。
为什么错:finally块无论是否发生异常、无论try/catch中是否有return,都会执行。且当finally中有return语句时,它会覆盖try/catch中的return值。本题finally中return 3强制返回3,catch的return 6被丢弃。

3.5 泛型类型擦除:题目19和20的“编译期幻觉”

错在哪:题目19中<T extends Comparable>声明泛型方法,认为运行时能获取T的具体类型(如Integer或String)。
为什么错:Java泛型是类型擦除实现,编译后T被替换为Comparable,minmax方法在JVM中只有一个字节码版本。ArrayAlg.minmax(arrI)和ArrayAlg.minmax(words)调用的是同一个方法,T的类型信息在运行时不存在。这也是为什么题目20中fromArrayToCollection(ia, cn)能成功——ia是Integer[],cn是Collection<Number>,Integer是Number子类,擦除后T统一为Number,类型检查在编译期完成。


4. 异常处理专项:从分类到finally的终极控制权

4.1 异常分类的本质:Throwable树的权力结构

题目3问所有异常的父类,答案是Throwable(B选项)。但题目2补充说明“内部错误(如硬盘损坏)”和“运行时异常(如除零)”,这暴露常见误解:Error和Exception不是并列关系,而是Throwable的两个直接子类。Error表示JVM无法恢复的严重问题(如OutOfMemoryError),Exception分为RuntimeException(unchecked,编译器不强制处理)和IOException等checked异常(编译器强制try/catch或throws)。题目4说“除数为零、负数索引、打开不存在文件都会抛异常”,完全正确——前两者抛RuntimeException子类,后者抛IOException(checked异常)。

4.2try-catch-finally的执行顺序:题目8的“流程图陷阱”

题目8代码:

try{ System.out.print("try,"); return; } catch(Exception e){ System.out.print("catch,"); } finally { System.out.print("finally"); }

输出是"try,finally"(C选项)。关键点在于:return语句在try中执行时,先记录返回值,再执行finally,最后返回。finally中无return时,原return值不变;有return时,finally的return覆盖原值(如题目9)。catch块完全不执行,因为try中无异常。

4.3 自定义异常的实践规范:题目11的throw与throws分界

题目11要求输入"abc"时抛异常,代码中throw new MyException("输入的字符串不正确!")正确。但易错点在于:MyException继承Exception(checked异常),因此main方法必须声明throws MyException或用try-catch包裹。参考代码未声明throws,却直接throw,编译会失败!正确写法是:

public static void main(String[] args) throws MyException { // 必须声明 if(strIn.equals("abc")) throw new MyException("输入的字符串不正确!"); }

若继承RuntimeException,则无需声明,但业务异常通常用checked异常,强制调用方处理。

4.4NullPointerException的精准定位:题目7的String构造陷阱

题目7中String strTest = new String(str);当str=null时抛NullPointerException(C选项)。注意:String构造函数public String(String original)的源码中,第一行就是Objects.requireNonNull(original),明确拒绝null。这比String.valueOf(null)更激进——后者返回"null"字符串,前者直接炸。


5. 编程题实战:从日期计算到泛型集合的落地编码

5.1 日期计算:题目12与14的工业级写法

题目12用Calendar加10天,但cal.get(Calendar.MONTH)+1是硬编码补救,脆弱。现代写法应使用java.time(Java 8+):

import java.time.LocalDate; import java.time.format.DateTimeFormatter; public class Ex12 { public static void main(String[] args) { LocalDate now = LocalDate.now(); LocalDate future = now.plusDays(10); DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); System.out.println("10天后的日期为:" + future.format(fmt)); } }

LocalDate不可变、线程安全,plusDays语义清晰,DateTimeFormatter避免手动拼接。题目14的毫秒差计算在跨时区场景会出错,正确做法是:

long days = ChronoUnit.DAYS.between(c1.toInstant(), c2.toInstant());

5.2 泛型集合:题目21与22的类型安全强化

题目21用List<Student>存储通讯录,但toString()方法未重写phone字段格式,输出为Student@12345。必须重写:

class Student { private String name; private String phone; // 构造器、getter... @Override public String toString() { return String.format("%s: %s", name, phone); // 格式化输出 } }

题目22的HashMap<String,String>实现翻译,但未处理键不存在情况:map.get("Banana")返回null,打印"Banana翻译:null"。应增加判空:

String translation = map.get(test); System.out.println(test + "翻译:" + (translation != null ? translation : "未找到"));

5.3 输入解析:题目18的健壮性补丁

题目18用Scanner按-分割输入,但未处理输入格式错误(如"3-abc-2.1"导致nextInt()抛InputMismatchException)。增强版:

public class Ex18 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请依次输入重量、包数、价格,并以-分隔:"); String input = scan.nextLine(); String[] parts = input.split("-"); if (parts.length != 3) { System.out.println("输入格式错误:需三个数字,用-分隔"); return; } try { int weight = Integer.parseInt(parts[0]); int bags = Integer.parseInt(parts[1]); double price = Double.parseDouble(parts[2]); System.out.println("销售总额为:" + weight * bags * price); } catch (NumberFormatException e) { System.out.println("输入包含非数字字符"); } } }

6. 答题技巧:用“三步验证法”拿下每道编程题

6.1 第一步:静态检查——编译器能发现的5类硬伤

  • 类型不匹配:int i = "123";(字符串赋值给int);
  • 未初始化变量:int x; System.out.println(x);(局部变量必须显式初始化);
  • 访问权限错误:private成员在类外直接调用;
  • 泛型不安全操作:List list = new ArrayList(); list.add("str"); String s = (String)list.get(0);(缺少泛型声明,强制转换风险);
  • 异常未处理:FileReader fr = new FileReader("a.txt");(FileNotFoundException是checked异常,必须try/catch或throws)。

6.2 第二步:动态推演——手算3轮循环/递归的关键状态

以题目13的Stack类为例,不运行代码,手推main方法:

  • stack.add("1")→list = ["1"](头插);
  • stack.add("2")→list = ["2","1"];
  • stack.add("3")→list = ["3","2","1"];
  • stack.get()→list.getFirst()="3";
  • stack.delete()→list.removeFirst()→list = ["2","1"];
  • stack.get()→"2"。
    输出应为3和2,与参考代码一致。此法可避LinkedList索引越界类错误。

6.3 第三步:边界穷举——每个参数至少测3个值

对题目16的parseInt(str,16):

  • 正常值:"200"→512(16进制200=十进制512);
  • 边界值:"0"→0,"F"→15;
  • 异常值:"G"→NumberFormatException(16进制不含G)。
    同理,String.valueOf(char[], int, int)需测:offset=0、offset=数组长度(越界)、count=0(返回空字符串)。

6.4 押题思路:近3年必考的3个“组合考点”

  • 集合+泛型+异常:如“用HashMap<String, List<Integer>>存储学生成绩,输入学生名查询,若不存在则抛自定义异常”;
  • 日期+字符串+IO:如“读取文件中日期字符串(格式yyyy-MM-dd),计算距今天数,写入新文件”;
  • 多态+封装+构造器:如“定义Shape抽象类,Circle和Rectangle子类,getArea()方法,用List<Shape>存储并遍历计算总面积”。

从那以后我每次写完代码,都强制走一遍这三步:先让编译器骂一遍,再拿笔在纸上画两轮数据流,最后对着输入框狂敲null、空格、超长字符串。不是为了炫技,是让肌肉记住——那些NullPointerException、IndexOutOfBoundsException、ClassCastException,从来不是天降神罚,而是你漏掉的一个!= null、一个< list.size()、一个instanceof。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询