news 2026/9/28 14:30:02

Java常用类编程题8-15:核心考点与易错细节全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java常用类编程题8-15:核心考点与易错细节全解析

"sdut-Java面向对象-10 常用类(编程题8-15)"——如果你是从实验平台的题目列表里看到这个编号再点进来的,那你大概率正在被一门Java课程作业折腾。这类编号在很多学校的OJ上都能见到,"sdut"是学校或平台标识,"面向对象"是课程模块名,后面的"常用类"才是这一节真正要考察的内容。从第8题排到第15题,一共8道,前面通常还有更简单的题在给你热身。

第一次带学生过这套题的时候,我发现一个很有意思的现象:你问班上的同学"常用类会了吗",十个里有八个说会,但把提交记录翻出来看,能一次通过的往往不到一半。问题不出在语法上,而是这些题恰好卡在"你自以为会、但没真正掌握细节"的API上。这篇帖子不打算给你一个标准答案式的题解,而是带着你把这8道题背后真正想让你掌握的东西、容易踩的坑,以及上机时怎么快速定位问题,完整梳理一遍。正在做这套作业的同学可以直接对照复习,想系统过一遍Java常用类知识点的初学者也能从中拿到干货。

1. 先弄清楚这组题到底想考什么

1.1 标题里的信息量

"sdut-Java面向对象-10"我理解成课程模块编号,"常用类(编程题8-15)"就是本模块的编程练习。题目排到第15,前面的编号大概率还在讲类与对象、继承、多态,到这一节突然变成String、包装类、日期、正则,很多同学会有一种"是不是走错实验室"的错觉。

其实老师安排顺序是有讲究的:学完类的封装和多态以后,你已经具备读JDK文档的能力,这时候再回头去补那些天天见、天天用的内置工具类,以后写复杂项目才不至于在基本功上卡壳。换句话说,这8道题不是一个独立的小考试,而是连接"面向对象语法"和"实际开发常用API"的桥梁。也正因为如此,题的表面难度都不高,真正拉开差距的往往是细节——哪些方法返回什么类型、边界值怎么处理、异常什么时候抛、输出格式跟样例一致不一致。

1.2 考点分布

每个学校出的具体题面可能不一样,但我把常见的"常用类"实验编程题做了个归纳,范围非常固定,基本逃不脱下面这几块:

考点模块核心API常见题型
StringcharAt、substring、equals、toCharArray字符统计、反转、判断回文
StringBuilderappend、reverse、length拼接效率、反转字符串
正则表达式String.matches、Pattern、Matcher手机号/邮箱格式校验
包装类Integer.parseInt、valueOf字符串与数字互转、异常捕获
Math和Randomabs、sqrt、pow、round、nextInt数学计算、随机数生成
日期时间LocalDate、DateTimeFormatter、ChronoUnit日期差、格式化输出

老师出的8道题具体描述可能跟下面我写的对不上号,但考法是同一套。下面我按题号展开,每道题给出核心解法和必须注意的坑。

2. 字符串这块如何稳定满分(题8-10)

2.1 题8:字符分类统计

这是非常经典的"拿新API练手"的题目。题面通常是:接收一行字符串,统计其中英文字母、数字、空格和其他字符的个数,并分别输出。

看到"统计字符串中各种字符"时,第一反应是用for循环配合charAt遍历每个字符,然后用Character工具类判断类型。Character.isLetter、isDigit、isWhitespace比手写ASCII码范围要安全得多,但这里有个隐藏坑:Character.isLetter对中文字符也会返回true。如果题目明确要求"英文字母",那你就不能只靠isLetter,还得再套一层判断。稳妥写法是直接判断ASCII范围:

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.nextLine(); int letter = 0, digit = 0, space = 0, other = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { letter++; } else if (c >= '0' && c <= '9') { digit++; } else if (c == ' ' || c == '\t') { space++; } else { other++; } } System.out.printf("letter=%d,digit=%d,space=%d,other=%d%n", letter, digit, space, other); sc.close(); } }

这里我把空格判断写成了== ' '或\t,而不是用Character.isWhitespace。原因后面详见踩坑篇,但可以提前说一句:isWhitespace会把换行、回车、全角空格也算进去,在某些OJ数据下会产生统计偏差。这一类题还有一个处理细节:如果读进来的字符串本身是空的,for循环不会执行,四个计数全是0,输出也要正常,很多人的代码在空串场景下会忘记考虑这一点而直接输出空行。

2.2 题9:反转与回文判断

常见问法一:输入字符串,输出反转后的结果;常见问法二:判断字符串是否回文。这两道共用同一个知识点:StringBuilder的reverse()方法。

如果你用for循环倒着遍历再拼字符串,也不是不行,但明显啰嗦。更关键的是,用String拼接会在循环里频繁创建新对象,小规模数据看不出差别,但老师批改时看代码风格也会扣分。回文题最优雅的写法:

String s = "abcba"; String reversed = new StringBuilder(s).reverse().toString(); if (s.equals(reversed)) { System.out.println("yes"); } else { System.out.println("no"); }

这里有两个知识点必须同时掌握。第一,new StringBuilder(s).reverse()返回的是StringBuilder对象,要输出或比较得先toString()转回String。第二,字符串比较要用equals,不能用==。我带作业时发现不少人用s == new StringBuilder(s).reverse().toString()去判断,结果不管是不是回文都输出no,而且在本地打印出来看两个字符串长得一样,怎么查都查不出来,最后只能一步步debug看内存地址才发现是==的问题。这个坑会在后面单独讲。

2.3 题10:String与StringBuilder的拼接效率对比

这道题在OJ里通常不会只让你"对比一下",而是给一个具体场景:把0到9999这些数字拼成一个超长字符串,统计拼接耗时,或者输出最终字符串长度。核心考点有两个:String不可变,每次+=都会创建新对象;StringBuilder可变,append是在原对象上直接修改。

实测数据很夸张。循环10万次,String拼接可能需要好几秒,StringBuilder基本是几十毫秒的量级。我自己机器上跑过一次,String拼接10万次耗时约3.8秒,StringBuilder是11毫秒,差距超过300倍。这不是作业题被人为放大,而是真实开发中String不可变带来的经典性能问题。

long start1 = System.currentTimeMillis(); String str = ""; for (int i = 0; i < 100000; i++) { str += i; } long end1 = System.currentTimeMillis(); StringBuilder sb = new StringBuilder(); long start2 = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { sb.append(i); } long end2 = System.currentTimeMillis(); System.out.println("String耗时: " + (end1 - start1) + "ms"); System.out.println("StringBuilder耗时: " + (end2 - start2) + "ms");

这里有个实际体验:有些OJ的评测机CPU很快,10万次循环耗时打印出来是0ms,看起来很不直观。遇到这种情况,把循环次数加到100万,或者改用System.nanoTime()输出纳秒级耗时,数据才有说服力。另外注意别把两个计时变量的赋值顺序写反,否则算出来的时间差是负数——这种低级错误在批改记录里我见过不止一次。

3. 非字符串类的常用类怎么拿分(题11-15)

3.1 题11:用正则校验手机号

这题几乎是必出的。题面一般是:输入一个手机号,判断格式是否合法,输出true或false。真正的考点有两个:一是你看不看得到String.matches这个方法;二是你知不知道在Java字符串里写正则时,反斜杠本身还需要转义。

正确写法:

String regex = "^1[3-9]\\d{9}$"; boolean ok = phone.matches(regex);

注意是\\d,不是\d。初学者经常在正则里只写一个反斜杠,编译器直接报"Invalid escape sequence"。另外,String.matches是做全字符串匹配的,所以正则开头结尾的^和$可写可不写,写了也不影响结果,反而更直观。

如果题面升级成"从一段长文本里找出所有合法的手机号",matches就不好使了,因为matches要求整个字符串完全匹配。这时候要用Pattern和Matcher的find方法做部分匹配:

Pattern p = Pattern.compile("1[3-9]\\d{9}"); Matcher m = p.matcher(text); while (m.find()) { System.out.println(m.group()); }

find是部分匹配,matches是全量匹配,这个区别值得记牢。另外正则题有个常见变体:校验邮箱。邮箱正则比手机号复杂一点,常见写法是^\\w+@\\w+(\\.\\w+)+$,同样注意\\w需要转义。

3.2 题12:包装类与字符串转数字

常见场景:输入若干行字符串,每行可能是数字也可能不是,把所有能转成数字的求和输出。如果直接Integer.parseInt,遇到"abc"会直接抛NumberFormatException,OJ判你运行时错误。关键代码是要捕获异常:

try { int num = Integer.parseInt(s); sum += num; } catch (NumberFormatException e) { System.out.println("非法数字: " + s); }

看起来简单,但每年都有不少人在try-catch的位置上翻车。要么没catch住,要么把try块放在循环外头,导致一个坏数据直接打断整个输入流程。正确思路是一行一行读,一行一行判断,不要把整个输入包在一个大try里面。

顺带提两个容易在选择题或附加题里出现的点。第一,Integer.parseInt返回int,Integer.valueOf返回Integer对象,两者有本质区别。第二,Integer类对-128到127做了缓存,valueOf在这个范围内返回缓存对象,超过范围才new新对象。所以Integer a = 100; Integer b = 100; a == b的结果是true,如果换成200,结果就是false。这个知识点经常作为包装类内容的延展被拿出来考。

3.3 题13:Math类计算

考题形式非常多,比如求指定半径的圆面积、求一个数的绝对值和平方根、四舍五入到两位小数。考察点集中在Math的几个静态方法:abs、sqrt、pow、round、PI。

给一个完整例子:输入半径r,输出圆面积,结果保留两位小数。

double area = Math.PI * Math.pow(r, 2); System.out.printf("%.2f%n", area);

Math.PI是double类型的圆周率,比你自己写3.14要精确。Math.pow(r, 2)是r的平方,比r * r更通用,尤其指数不是整数时只能用pow。round是做四舍五入的,但要注意负数的行为:Math.round(-11.5)的结果是-11,不是-12,因为它是向正无穷方向取整。遇到负数取整需求,别直接套round,先想清楚题目要的是"四舍五入"还是"绝对值四舍五入再带符号"。这类边界问题在Math类题目里是最容易丢分的角落。

3.4 题14:Random生成指定范围随机数

这题一般出成:连续生成10个[1,100]之间的随机整数并输出。很多人第一反应是(int)(Math.random() * 100) + 1,这样确实能出结果,但如果题目特意写了"使用Random类",还是用正主:

Random r = new Random(); for (int i = 0; i < 10; i++) { System.out.println(r.nextInt(100) + 1); }

new Random()不传种子时,默认用系统纳秒时间做种子,每次运行结果都不一样,满足"随机"的预期。nextInt(n)返回的是[0, n)之间的整数,所以想要[1,100]就写nextInt(100) + 1。容易错的地方是写成nextInt(101),然后以为自己拿到了1到101,实际上得到的是0到100。

我的经验是把它记成一个公式:要生成[a, b]区间的整数,用nextInt(b - a + 1) + a。不管题面怎么变,套这个公式绝对不会错。另外注意nextInt()不带参数时返回的是整个int范围的随机数,可能包含负数,除非题目明确要求,否则别这么用。

3.5 题15:日期时间处理

最后一题基本是日期。如果平台用的JDK是8及以上版本,强烈推荐用LocalDate,别再用Date加Calendar。比如题目要求:输入两个日期,计算它们之间相差多少天。

import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate d1 = LocalDate.parse("2024-01-01", fmt); LocalDate d2 = LocalDate.parse("2024-12-31", fmt); long days = ChronoUnit.DAYS.between(d1, d2); System.out.println(days);

LocalDate.parse默认就能解析yyyy-MM-dd这样的格式,所以中间的fmt其实可以省略。不过建议保留,因为题目可能会要求在输出时指定别的格式,比如2024年01月01日,那时候你就得自己ofPattern了。

日期这一块有三个细节必须注意。第一,格式化串里MM是月份,mm是分钟,写错一个字母解析就直接崩。第二,Calendar的月份从0开始,也就是Calendar.JANUARY == 0;而LocalDate的getMonthValue()从1开始,更符合日常习惯,这也正是我推荐LocalDate的核心理由。第三,ChronoUnit.DAYS.between返回的是long,如果两个日期差超过int范围,int会溢出,虽然OJ数据很少这么大,但习惯性用long更稳妥。

4. 上机实测最容易翻车的五个细节

4.1 字符串比较用==还是equals

这个问题老生常谈,但永远在重复发生。用==比较String比较的是引用地址,只有equals才比较内容。存在一个例外:字符串常量池。String a = "hello"; String b = "hello";时,a == b的结果是true,因为两个字面量指向同一个常量池对象;但如果其中一个是用new String("hello")创建的,结果就是false。

这种不一致最容易给初学者造成"==有时候能用"的错觉。我的建议是:写代码时一律用equals,别去赌那道例外。尤其在做OJ题时,你压根不知道测试数据是用什么方式构造的字符串,用equals是唯一稳的做法。这也是题9回文判断里最该记住的一条。

4.2 Character.isWhitespace与空格的差异

前面题8提过,Character.isWhitespace会把制表符、换行、回车、全角空格都算成空白。如果题目说"统计空格字符",标准答案很可能只认' '字符本身。为了不在这上面丢分,你可以先想清楚题目到底要的是什么:统计的是"空格键"还是"所有空白符"。

我个人的处理原则是:OJ题优先按字面意思来,题目说空格就只认' ',必要时再把\t单独考虑。宁可多判断几个值,也别用一个语义过宽的API,否则测试数据里混入一个全角空格,你的统计就会跟标准答案差了1个,最后怎么查都查不到原因。

4.3 nextInt和nextLine混用的坑

如果题目是先读一个整数n,再读n行字符串,你可能会写出这样的代码:

int n = sc.nextInt(); for (int i = 0; i < n; i++) { String s = sc.nextLine(); }

然后就会发现第一行字符串永远读不到。原因是nextInt读取后会在缓冲区里留下一个换行符,随后的nextLine直接把这个换行符当字符串读走了。解决办法是在nextInt后面补一句sc.nextLine(),把残留的换行消费掉:

int n = sc.nextInt(); sc.nextLine(); for (int i = 0; i < n; i++) { String s = sc.nextLine(); }

这个坑在字符串统计、正则校验这类题目里非常常见,一旦出现能卡你半小时。如果题目输入的是"数字和字符串交替出现",强烈建议全部用nextLine读取,再自己用Integer.parseInt转换数字,这样彻底避开混用问题。

4.4 随机数的区间边界

作业里偶尔会出现这种场景:题目说生成0到9的随机数,用nextInt(10)没问题;但有人说"生成0到10的随机数",随手写nextInt(10),完全没意识到少了边界。nextInt(n)取的是[0, n),永远到不了n本身。

还是那句话,遇到[a,b]区间,先算b - a + 1,再套nextInt(b - a + 1) + a,一秒钟定位正确答案。另外,如果题目要求每次运行时随机数序列完全一样,比如为了调试方便,可以给Random传一个固定种子,比如new Random(42),这样每次运行生成的都是同一组数,方便复现问题。但OJ最终评测用的是默认随机,所以提交前记得把种子去掉。

4.5 浮点数输出的格式问题

涉及Math类计算时,题目往往会要求保留若干位小数。用System.out.printf("%.2f", x)是正确做法。有人图省事直接用println输出原始double,结果3.141592653589793跟预期答案对不上,被判WA。

另一个容易忽略的是精度差异。题目如果明确说"π取3.14",那你就别用Math.PI;反过来,如果题目说"使用Math类计算",那用Math.PI才符合要求。两种写法在保留两位小数时可能结果一样,但在某些精度要求更高的题里会差最后几位。判断标准只有一个:题目有没有明说近似值。没说就用Math.PI,说了就按题面来。

5. 做题顺序与最终自查清单

5.1 我建议的做题顺序

如果这8道题你自己安排练习顺序,别按题号从8到15硬刷。我的习惯是先做String和包装类,再做Math和Random,最后碰正则和日期。理由是:字符统计、反转这些题能帮你热手,把对API的疏离感先消掉;正则和日期需要背的知识点最多,放到后面集中记忆,效果反而更好。

另外,题10的String与StringBuilder效率对比题,其实是"理解原理"型题目,它不像题8那样有标准输出可以对照,更像是小实验。这类题在OJ上通常只验证你输出了耗时数据和最终结果,逻辑比较简单,也可以提前做。但如果你想真正理解StringBuilder和String的区别,多做几遍题9的反转会更有帮助,因为reverse直接暴露了可变与不可变两种操作方式的差异。

5.2 提交前自查清单

每个题提交前,我都按下面这个清单过一遍。这个习惯帮我少交了很多次无效提交:

  • 类名是否为Main,public static void main(String[] args)签名是否完整
  • 题目要求的输入方式是nextLine还是next,有没有混用
  • 是否打印了多余提示语,比如"请输入:"这种干扰OJ判断的语句
  • 边界数据:空串、单字符、负数、最大值,逐一想一遍
  • 输出格式:换行、逗号、冒号是否与输出样例完全一致
  • 涉及数字转换时,是否catch了NumberFormatException
  • 用了中文标点的地方是否全部改成英文标点,OJ输出比对的是Unicode码点,一个全角符号都不行

说回开头那句话,这组题真正拉开差距的不是会不会写代码,而是对API边界的把握是否到位。我当年第一次做类似的题,在nextInt和nextLine混用上卡了四十分钟,后来把这些坑一个一个记下来,才发现所谓"常用类"不过是一堆有脾气但可驯服的工具。如果你们学校的具体题面跟我提到的对不上,也别慌,知识点是通用的——把String的equals、StringBuilder的reverse、包装类的parse、正则的转义、LocalDate的格式化这几个核心点吃透,换汤不换药。

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

Coding Agent 终端输出剪枝:Token 消耗降 98%,上下文不再爆仓

最近在项目里重度使用 Coding Agent 做日常开发&#xff0c;我最大的感受是&#xff1a;这玩意儿确实是干活利器&#xff0c;但论吃 Token 的速度&#xff0c;也确实是刺客级别的。尤其是当你让它自己跑一遍构建、执行一轮测试&#xff0c;终端里哗啦啦滚出上千行日志&#xff…

作者头像 李华
网站建设 2026/9/28 14:28:39

普通人可用的四款开箱即用智能体工具实操指南

1. 这不是“AI编程课”&#xff0c;是普通人真正能上手的智能体实操路径最近在几个技术社群里&#xff0c;总有人发问&#xff1a;“想试试智能体&#xff0c;但一打开GitHub就头晕&#xff0c;看到LangChain文档第一页就想关网页——有没有那种插上电就能用、不用配环境、不写…

作者头像 李华
网站建设 2026/9/28 14:28:37

MySQL报错 Field doesn‘t have a default value 根因排查与修复方案

工作这么几年&#xff0c;MySQL 的报错见过不少&#xff0c;但有一种错看着特别“不科学”&#xff0c;第一次碰上会让人愣好半天&#xff1a;Field remark doesnt have a default value明明 SQL 语句里字段、值一一对得上&#xff0c;语法也没问题&#xff0c;凭什么报“没有默…

作者头像 李华
网站建设 2026/9/28 14:28:33

FlashInternImage图像分类实战:架构解析、训练技巧与避坑指南

简介&#xff1a;面向计算机视觉研究者与深度学习开发者的FlashInternImage图像分类实战资料包&#xff0c;基于DCNv4替换DCNv3构建模型&#xff0c;无需额外改动即可获得最高80%的速度提升和更强的性能表现。内容围绕图像分类任务展开&#xff0c;覆盖从模型构建、训练到评估的…

作者头像 李华
网站建设 2026/9/28 14:28:32

UDS刷写实战:34/36/37服务协同原理与产线级排错

1. 这不是教科书里的UDS&#xff0c;是修车厂里真刀真枪刷写的实战笔记你手头有一台故障码报“P0606 ECU内部RAM校验失败”的老款大众迈腾&#xff0c;4S店说要换整套ECU总成&#xff0c;报价八千&#xff1b;你拆开ECU外壳&#xff0c;发现主控芯片型号是Infineon TC275&#…

作者头像 李华
网站建设 2026/9/28 14:27:03

回溯算法核心:组合总和、去重与回文切割的实战解析

1. 回溯算法最容易被低估的关卡&#xff1a;组合与切割的底层逻辑刷题刷到代码随想录Day20&#xff0c;三道题摆在一起看其实挺有讲究的&#xff1a;39组合总和、40组合总和II、131分割回文串。很多人在这个节点上会突然卡壳&#xff0c;因为前面刚熟悉了二叉树和递归的节奏&am…

作者头像 李华