资讯动态

Java常用类编程题深度解析:String、包装类与日期格式化避坑指南

发布时间:2026/10/1 12:13:59 来源:尧图企业网站定制
刚帮人调试完一套 SDUT 的 Java 面向对象作业——就是那份“常用类编程题1-7”发现不少人在 String、包装类、日期格式化这些“看起来很简单”的题上栽跟头。这门课讲到常用类这个阶段考察的已经不是语法背得熟不熟而是你有没有真正理解类的行为、方法的设计意图和边界条件。今天就把这套题背后最值得抠的知识点、我踩过的坑、以及怎么在 OJ 上稳定通过的经验一次性说透。1. 这套常用类题到底在考什么拆开题目表面的“马甲”先说结论SDUT 这套“面向对象-10 常用类”的编程题题型翻来覆去就是那几类——字符串处理、包装类与数值转换、Math 与随机数、日期格式化与 Calendar 操作。很多同学觉得题难不是因为语法不会而是没搞懂每道题真正想测试的知识点被题目描述里的业务包装带偏了。1.1 考点集中营一套题覆盖五个核心类我统计了一下这类题目的高频考点分布基本是这样一个格局核心类典型考法隐藏考点String字符统计、子串截取、反转、替换不可变性、equals 与 的区别StringBuffer / StringBuilder大量字符串拼接、逆序输出与 String 的性能差异、线程安全包装类字符串转 int、进制转换、比较大小自动装箱/拆箱、Integer 缓存机制Math绝对值、幂运算、四舍五入、随机数静态方法特性、random 的区间Date / Calendar / SimpleDateFormat日期输出、计算天数差、格式化SimpleDateFormat 线程不安全、月份从 0 开始你去看那 7 道题基本逃不出这张表的范围。题目可能会包装成“统计一句话里每个字母出现的次数”“把 MM/dd/yyyy 格式的日期转换成 yyyy-MM-dd”“模拟一个抽奖程序”之类的业务场景但剥开壳子内核全是上面这些 API 的调用和边界处理。1.2 为什么说这阶段是“面向对象”的转折点如果你只把这套题当“API 背诵测试”那就亏大了。实际上“常用类”在 Java 课程体系里是一个非常特殊的位置——它不再让你自己定义类而是让你学会“使用别人定义好的、设计精良的类”。这背后其实是面向对象思维的第二次跃迁第一阶段是“万物皆对象”自己写 class、new 对象、调方法第二阶段是“别人写的类也是对象”你要去读 JDK 文档理解 String 为什么重写了 equals理解 Integer 为什么有缓存理解 SimpleDateFormat 为什么不是线程安全的。所以做这 7 道题的时候别只为了通过 OJ 的测试用例。每道题做完之后多问自己一句这个类的作者为什么这么设计把这句话想明白了后面学集合框架、IO 流、多线程会顺畅非常多。2. String 类题型这三个细节比背 API 重要得多7 道题里通常有一半左右涉及字符串处理这是整套题的大头。字符串题最容易出现的雷区我一个个说都是 OJ 上真实见过的错误。2.1 equals 和 一个判断引发的“悬案”这是老生常谈但在 OJ 题里依然有大把人中招。先看一段我经常在学生的提交里见到的代码Scanner sc new Scanner(System.in); String flag sc.next(); if (flag yes) { // 错误 // ... }为什么错了因为比较的是引用地址而equals比较的是字符序列内容。这里有个非常隐蔽的细节如果输入是String flag yes直接字面量赋值flag yes很可能返回 true因为都指向常量池里的同一个对象。但一旦输入来自sc.next()JVM 返回的就不是常量池里的那个对象了返回 false。这不是“玄学”而是 String 的 intern 机制。记住一句话字符串内容比较永远用equals不要图省事用。我见过有同学因为第一次测通过了后面所有题都写结果换一个数据就 WA还找不到原因就是这个细节。2.2 不可变性为什么字符串拼接别用 String有一类题是“把一句话里的单词顺序反转”或者“拼接 n 个字符串”。很多新手这样写String result ; for (int i 0; i n; i) { result input[i] ; }功能上没错但如果在 OJ 上数据量大、循环次数多就可能超时。原因是 String 是不可变对象每次都会创建一个新的 String 对象旧的就被丢弃。循环 10000 次就创建了 10000 个中间对象垃圾回收压力巨大。正确做法是用 StringBuilder单线程场景下够用或者 StringBuffer线程安全但性能稍差StringBuilder sb new StringBuilder(); for (int i 0; i n; i) { sb.append(input[i]).append( ); } String result sb.toString().trim();这套题里凡是涉及“拼接”“反转”的我都建议直接用 StringBuilder。记住它的常用 APIappend、reverse、toString。尤其是reverse()处理“反转字符串”题简直是一行答案String reversed new StringBuilder(s).reverse().toString();2.3 边界问题substring 和 charAt 的下标陷阱字符串题目里另一个高频 WA 原因就是下标越界或者取错区间。substring(beginIndex, endIndex)是左闭右开——取beginIndex位置开始到endIndex-1位置结束。比如Hello.substring(1, 3)结果是el不是ell。还有一个特别容易错的地方把字符串反转后和原字符串比较判断回文。如果你用 charAt 逐字符比较循环条件怎么写我见过有人写for (int i 0; i s.length(); i)直接 StringIndexOutOfBoundsException。正确应该是i s.length()或者用双指针int left 0, right s.length() - 1; while (left right)这样既避免越界又少比较一半。做题技巧凡是涉及下标、长度的题目先自己手动模拟一遍把边界情况空字符串、单个字符、最大长度写出来测试一遍再提交。这类题 WA 一次代价很高——SDUT 的 OJ 往往有时间限制和提交次数记录养成“先测边界再提交”的习惯能省很多事。3. 包装类与装箱拆箱数值转换题里的隐形杀手字符串转数字、数字转字符串、进制转换——这些题看着人畜无害实际上包装类机制里有好几个隐蔽的坑。3.1 Integer 缓存为什么 128 和 127 的结果不一样如果题目里让你比较两个 Integer 对象的大小又出来坑人了。看这段代码Integer a 127; Integer b 127; System.out.println(a b); // true Integer c 128; Integer d 128; System.out.println(c d); // false输出结果居然不一样很多第一次见这个结果的初学者直接懵了。原因Integer 类内部维护了一个缓存池默认缓存 -128 到 127 之间的 Integer 对象。Integer a 127实际上触发自动装箱调用的是Integer.valueOf(127)而 valueOf 有个判断如果值在缓存范围内直接返回缓存对象超过范围才 new 一个新对象。所以a和b指向同一个缓存对象是 truec和d各 new 了一个对象是 false。这题如果要求比较两个大数的“值”一定要用a.intValue()或者a.equals(b)。用 equals 是正确的因为 Integer 重写了 equals 来比较值。3.2 parseInt 与 valueOf别把返回类型搞混字符串转 int 的题里Integer.parseInt(String)返回的是原始类型 intInteger.valueOf(String)返回的是包装类型 Integer。大多数场景两者效果差不多但有一个关键区别valueOf 会走缓存机制如果数值在 -128~127。虽然这个区别不影响做题答案但如果你写代码时把一个 Integer 赋给 int就涉及自动拆箱一旦这个 Integer 是 null立刻抛 NullPointerException。有个在 SDUT 题里很经典的场景——从输入里读一个字符串表示的数字然后和某个 int 比较大小int n Integer.parseInt(sc.nextLine().trim());这里我特意加了.trim()因为nextLine()取到的字符串可能带首尾空格parseInt对空格是敏感的只要有空格就抛 NumberFormatException。如果用的是nextInt()就没有这个问题但它不会吃掉末尾换行后续再用nextLine()会读到空串。这是 OJ 题的经典陷阱。3.3 进制转换方法一多就容易选错进制转换在常用类题目里经常以“10 进制转 16 进制”“8 进制转 2 进制”等形式出现。Java 提供了好几个相关方法很多人临场容易搞混Integer.toHexString(int)转 16 进制结果是字符串Integer.toOctalString(int)转 8 进制Integer.toBinaryString(int)转 2 进制Integer.parseInt(String, int radix)按 radix 进制解析字符串。这组方法里最容易翻车的是负数。Integer.toHexString(-1)的结果不是-1而是ffffffff因为它在内部是按补码来处理的。如果题目没明确说负数的处理规则提交前一定要测一下负数用例。另外转进制后如果题目要求大写形式的十六进制字母记得调用.toUpperCase()toHexString默认返回小写 a-f不转换直接交上去必 WA。4. Math、日期与格式化别小看这些“小工具类”相对字符串和包装类Math 和日期类的题考查的知识点比较固定但也正因为“看起来简单”很多人反而在细节上翻车。4.1 Math 类题型记住它全是静态方法就够了Math 类不需要 new 对象所有方法都是静态的直接Math.xxx()调用。高频考点包括Math.abs()取绝对值但要小心Math.abs(Integer.MIN_VALUE)返回的还是负数因为 int 范围不对称Math.pow(a, b)求幂返回 double如果需要 int 结果要强转Math.sqrt()求平方根输入负数返回 NaNMath.random()返回[0.0, 1.0)的随机 double左闭右开。是不是觉得没什么技术含量但实际题目里设计陷阱的方式很有意思。比如“生成 1 到 100 之间的随机整数”很多同学写成int num (int)(Math.random() * 100) 1;这就错了。Math.random()最大是0.999...乘 100 后最大是99.999...强转 int 是 991 之后是 100这样看没错。但最小的值是0.0乘 100 后是 01 后是 1。实际上这个式子生成区间确实是[1, 100]看起来没问题。可如果你随手写(int)(Math.random() * 100)不加 1那生成的是[0, 99]漏掉了 100 这个边界。题目如果要求“包含两端”一定要检查随机数公式的边界。还有个隐藏考点Math.round()的四舍五入规则。Math.round(2.5)返回 3Math.round(-2.5)返回 -2——注意它不是“远离零四舍五入”而是“向正无穷方向取最接近的整数”。很多题目涉及金额计算或评分统计负数场景一出现保守的同学立马算错。4.2 日期格式化SimpleDateFormat 的“线程安全”和月份 0 起点日期类的题目在 SDUT 常用类编程题里经常占 1 到 2 道核心考点是 Date、Calendar 和 SimpleDateFormat 的配合使用。第一个大坑是月份从 0 开始计数。Calendar cal Calendar.getInstance(); cal.set(2024, 12, 1); // 你以为的 12 月实际是下一年的 1 月Calendar.MONTH的取值是 0 到 110 代表一月。正确写法是cal.set(2024, Calendar.DECEMBER, 1)或者用cal.set(2024, 11, 1)。这是我见过的这阶段最高频的“逻辑错误”之一——编译不报错运行也不报错但计算结果差一个月整个答案就错了。第二个坑是 SimpleDateFormat 不是线程安全的。虽然初级题里只用单线程不涉及并发但我在帮人 review 代码时见过有人把它定义成 static 字段然后在方法里共享使用这个习惯非常差。如果后面学到多线程再沿用这个习惯就会出现诡异的结果时间的数据被冲掉、日期错乱、甚至抛异常。建议每题都 new 一个实例或者干脆学习使用java.time包下的LocalDate、DateTimeFormatter。不过要提醒一点很多学校的 OJ 用的 JDK 版本可能比较老java.time在 Java 8 里才引入。如果 OJ 环境是 Java 7用了 LocalDate 会直接编译失败。做题前先看下 OJ 支持的 Java 版本别学了个新特性结果环境不支持。还有格式化字符串的匹配问题。题目给的输入日期格式可能是yyyy/MM/dd你要输出yyyy年MM月dd日中间的“/”和“年”“月”这些分隔符必须和 pattern 完全对应。MM和mm是完全不同的含义——MM是月份mm是分钟。写错一个字母不会编译报错但输出结果全错这种题属于“白给型”细心一点就满分粗心一点就 WA。5. OJ 提交实战从 WA 到 AC 的完整排错链路聊完知识点最后说说这个阶段刷题最实用的“作战流程”。如果你这 7 道题里有几道第一次提交没过别慌按下面的排查路径走基本能把问题定位出来。5.1 拿到题目先做三件事而不是急着敲代码我自己的做题顺序是先花 5 分钟做“输入输出分析”比直接编码高效得多看清输入格式是一行一个测试数据还是多行有没有 T表示测试组数在开头每行末尾有没有多余空格看清输出格式每个结果占一行还是结果之间有空格/逗号有没有要求“Case #1:”这样的前缀找边界条件字符串可能为空吗数字可能是负数吗数值能大到超过 int 范围吗这三个问题的答案直接决定你代码里要不要做特殊处理。SDUT 的题目描述一般比较直白但也不会把边界条件写在显眼的位置需要你自己判断。比如字符串类题目如果没说“输入非空”你就得想想空字符串怎么处理如果没说“n 为正整数”0 和负数也得有说法。5.2 提交失败后的“二分定位法”遇到 WAWrong Answer我的做法是不要盯着代码干瞪眼而是构造“针对性测试数据”来缩小范围如果题目有一个样例输入先把样例跑通这是基本盘然后测边界值最大输入、最小输入、空输入、单字符输入再测特殊值负数、0、混合大小写、包含空格和标点符号的输入比如字符串反转题你样例过了提交 WA我就怀疑是不是输入里包含空格——sc.next()只读到空格前的内容读不完整句话。这种题必须用sc.nextLine()但用了nextLine()又要注意前面有没有nextInt()残留的换行符需要先sc.nextLine()把换行吃掉。这个“吃掉换行”的操作我见过的初学者至少有一半人不知道。如果是 RERuntime Exception优先查数组越界和空指针。定位方法用“二分注释”把代码里处理字符串的段落注释掉一半跑一次再注释另一半跑一次快速定位是哪个步骤崩的。虽然原始了一点但在 OJ 上比加断点调试要快太多。5.3 一套可以抄作业的输入输出模板最后送一个我自己写这类题用的基础模板能覆盖绝大多数 SDUT Java 编程题的输入输出场景import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); // 情形一先读一个整数 T表示后面有 T 组测试数据 int t sc.nextInt(); sc.nextLine(); // 吃掉 nextInt 后面的换行符 while (t-- 0) { String line sc.nextLine(); // 整行读取避免空格截断 // 处理逻辑... } // 情形二循环读取直到 EOF while (sc.hasNext()) { String s sc.next(); // 或 nextLine() // 处理逻辑... } sc.close(); } }类的名字必须是MainSDUT OJ 的硬性要求main 方法签名不能写错否则直接 CECompile Error。还有一点Java 代码在 OJ 上跑得比 C/C 慢如果题目的时间限制很紧尽量不要在循环里反复拼接 String能用 StringBuilder 就用。这套题刷完之后建议把 String、包装类、Math、SimpleDateFormat 的常用方法整理成一张速查表后面做课程设计、面试刷题都用得上。其实常用类这一章的学习目标就一个建立“查文档—用 API—处理边界”的思路。把这套题吃透你离脱离“照着书本敲代码”的阶段就又近了一步。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑