沙漏图案需用双重for循环控制空格与星号数量,总行数为奇数,上半部分第i行星号数为n-2i、空格数为i,下半部分第j行星号数为2j+1、空格数为(n-1)/2-j,注意JDK版本兼容性。

用双重 for 循环控制行与列的空格和星号数量
沙漏形状本质是两段对称递减/递增的三角形拼接,关键不在“图形思维”,而在算清楚每行要打几个空格、几个 *。比如总高度为 7(奇数),中间行是 1 个 *,往上每行多 2 个 *、少 1 个空格;往下同理。别硬记公式,直接按行号 i(从 0 开始)推:上半部分(含中间行)共 (n + 1) / 2 行,第 i 行的星号数是 n - 2 * i,左侧空格是 i;下半部分第 j 行(从 0 开始)星号数是 2 * j + 1,左侧空格是 (n - 1) / 2 - j。
常见错误是索引越界或空格数算反——比如把“上半部分第 0 行”当成最多星号那行,结果第一行就打满,沙漏变菱形。实际沙漏最宽在首尾,最窄在中间。
- 总行数必须是奇数,否则无法对称收束到单个
* -
System.out.print(" ")和System.out.print("*")别混成println,否则每打一个字符就换行 - 空格必须用半角空格,中文空格或制表符
\t会导致错位
避免 String.repeat() 在低版本 JDK 报错
JDK 11+ 才有 String.repeat(int),如果项目还在用 JDK 8,硬写 " ".repeat(spaces) 会编译失败。不是所有环境都能升级 JDK,得有兜底方案。
手写一个简易重复函数更稳妥,也便于调试空格逻辑:
private static String repeat(String s, int n) {
return new String(new char[n]).replace("\0", s);
}
或者直接用 for 循环拼接(小数据量无性能压力):
for (int k = 0; k
- 别依赖 IDE 自动补全的
repeat(),先确认java -version - 用
StringBuilder拼接再print也可以,但对单行几十字符来说没必要 - 如果输出到文件或日志,注意 Windows 换行符
\r\n可能影响对齐,统一用\n
对称图形扩展:从沙漏到任意中心对称图案
沙漏只是中心对称的一种。只要每行内容满足 line[i] == line[n-1-i],就能复用同一套行控制逻辑。比如把 * 换成 A、B 交替,或用 "*o*" 当单元块。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
真正卡住人的不是“怎么画”,而是“怎么让非固定字符也对称”。核心是把每行看作一个字符串生成任务,而非字符堆砌:
- 先确定该行总宽度(比如固定为
n),再决定中心位置填什么、左右镜像填什么 - 如果用字符数组构造,记得
char[]初始化后要显式赋值,否则是\0 - 不要在循环里反复调用
String.substring()或正则,简单图形纯靠计算更快
控制台输出错位?检查字体和终端宽度
代码逻辑全对,但看起来歪了——大概率不是 Java 的问题,是终端渲染导致的。等宽字体(如 Consolas、Monaco、JetBrains Mono)下空格和 * 宽度才一致;用微软雅黑或宋体,空格会被压缩,图形必然塌陷。
另外,IDE 内置终端可能默认宽度不够,比如只设了 80 列,而你的沙漏要 99 列,末尾就被截断或折行。这不是代码 bug,是环境适配问题。
- 在命令行(cmd / Terminal)中运行验证,比 IDE 终端更真实
- 临时加一行
System.out.println("WIDTH:" + " ".repeat(100));看是否显示完整 - Linux/macOS 下可查
tput cols,Windows 下用mode con查当前列宽
图形算法本身不难,难的是你永远不知道下一秒是逻辑错了,还是字体没设对。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










