Java 实例 – 打印矩形(长文讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在编程学习的旅程中,"打印矩形"是一个经典且基础的练习项目。它不仅能够帮助开发者掌握循环结构和条件判断的核心逻辑,还能通过不同变体(如空心矩形、带边框的矩形)训练代码设计的灵活性。本文将以"Java 实例 – 打印矩形"为主题,通过分层次的讲解和实例代码,带领读者从基础语法到进阶技巧全面掌握这一技能。无论是编程初学者还是希望巩固基础的中级开发者,都能从中获得实用的指导和启发。


理解矩形打印的核心逻辑

1. 矩形的数学模型与坐标系

矩形由高度(行数)和宽度(列数)决定。在代码中,我们可以将每一行视为一个"打印行",每一列视为该行中的字符位置。想象一个二维坐标系:

  • 行(Row):从上到下递增,通常用变量 i 表示
  • 列(Column):从左到右递增,通常用变量 j 表示

例如,一个 3x5 的矩形可以表示为:

行 0: [列0, 列1, 列2, 列3, 列4]  
行 1: [列0, 列1, 列2, 列3, 列4]  
行 2: [列0, 列1, 列2, 列3, 列4]  

这种坐标系的思维模式是解决打印问题的关键。

2. 循环结构的选择

打印矩形的核心在于双重循环:

  • 外层循环控制行数for(int i=0; i<行数; i++)
  • 内层循环控制列数for(int j=0; j<列数; j++)

例如,一个简单的矩形打印代码框架如下:

public class RectanglePrinter {  
    public static void main(String[] args) {  
        int rows = 3;  
        int cols = 5;  
        for(int i=0; i<rows; i++) {  
            for(int j=0; j<cols; j++) {  
                System.out.print("*"); // 打印字符  
            }  
            System.out.println(); // 换行  
        }  
    }  
}  

此代码将输出:

*****  
*****  
*****  

基础案例:实心矩形与空心矩形

1. 实心矩形(Solid Rectangle)

实心矩形的每个位置都填充字符(如 *)。上文的代码即为典型示例。关键点在于:

  • 内层循环的每一次迭代都打印一个字符
  • 外层循环结束后换行

2. 空心矩形(Hollow Rectangle)

空心矩形仅在边缘填充字符,内部为空。此时需要添加条件判断:

public class HollowRectangle {  
    public static void main(String[] args) {  
        int rows = 4;  
        int cols = 6;  
        for(int i=0; i<rows; i++) {  
            for(int j=0; j<cols; j++) {  
                if(i == 0 || i == rows-1 || j == 0 || j == cols-1) {  
                    System.out.print("*");  
                } else {  
                    System.out.print(" ");  
                }  
            }  
            System.out.println();  
        }  
    }  
}  

输出结果:

******  
*    *  
*    *  
******  

关键逻辑解释

  • 当处于第一行(i=0)、最后一行(i=rows-1)、第一列(j=0)或最后一列(j=cols-1)时打印 *
  • 其他位置打印空格

进阶技巧:动态参数与用户输入

1. 通过控制台输入参数

在实际开发中,矩形的尺寸通常需要动态指定。可以使用 Scanner 类读取用户输入:

import java.util.Scanner;  

public class DynamicRectangle {  
    public static void main(String[] args) {  
        Scanner scanner = new Scanner(System.in);  
        System.out.print("输入行数:");  
        int rows = scanner.nextInt();  
        System.out.print("输入列数:");  
        int cols = scanner.nextInt();  

        // 打印实心矩形的逻辑  
        for(int i=0; i<rows; i++) {  
            for(int j=0; j<cols; j++) {  
                System.out.print("*");  
            }  
            System.out.println();  
        }  
    }  
}  

2. 参数验证与异常处理

为避免用户输入负数或零,可以添加条件判断:

if(rows <= 0 || cols <= 0) {  
    System.out.println("行列数必须大于0");  
    return; // 终止程序  
}  

扩展应用:复杂形状与多维数组

1. 带边框的彩色矩形(使用ANSI转义码)

通过控制台颜色输出增强视觉效果:

public class ColorRectangle {  
    public static void main(String[] args) {  
        int rows = 5;  
        int cols = 10;  
        for(int i=0; i<rows; i++) {  
            for(int j=0; j<cols; j++) {  
                if(i == 0 || i == rows-1 || j == 0 || j == cols-1) {  
                    System.out.print("\033[44m" + "*" + "\033[0m"); // 蓝色背景  
                } else {  
                    System.out.print("\033[47m" + " " + "\033[0m"); // 白色背景  
                }  
            }  
            System.out.println();  
        }  
    }  
}  

注意事项

  • ANSI转义码在Windows系统中需启用支持(JDK 16+ 或通过命令 System.setProperty("java.awt.headless", "false")

2. 使用多维数组存储矩形数据

将矩形视为一个二维数组,可实现更复杂的逻辑(如填充图案):

public class ArrayBasedRectangle {  
    public static void main(String[] args) {  
        int rows = 3;  
        int cols = 4;  
        char[][] rectangle = new char[rows][cols];  

        // 初始化数组  
        for(int i=0; i<rows; i++) {  
            for(int j=0; j<cols; j++) {  
                rectangle[i][j] = (i == 0 || i == rows-1 || j == 0 || j == cols-1) ? '*' : ' ';  
            }  
        }  

        // 输出数组内容  
        for(char[] row : rectangle) {  
            System.out.println(new String(row));  
        }  
    }  
}  

性能优化与代码重构

1. 避免重复计算

在循环中,将 rows-1cols-1 存储为临时变量,减少计算次数:

int lastRow = rows - 1;  
int lastCol = cols - 1;  

2. 使用StringBuilder提升效率

对于大规模数据(如1000x1000的矩形),直接使用 System.out.print 可能导致性能问题。改用 StringBuilder 缓冲数据:

StringBuilder sb = new StringBuilder();  
for(int i=0; i<rows; i++) {  
    sb.setLength(0); // 清空缓冲区  
    for(int j=0; j<cols; j++) {  
        sb.append('*'); // 或其他字符  
    }  
    System.out.println(sb.toString());  
}  

常见问题与解决方案

1. 输出出现多余空格或换行

原因:在内层循环结束后,System.out.println() 会自动换行。若误将 printprintln 混用,会导致格式错乱。
解决方案:确保内层循环结束后仅调用一次 println()

2. 矩形尺寸不符合预期

原因:变量 rowscols 的值可能被错误赋值。例如,rows = 5 实际打印了5行,但用户可能误以为是6行。
解决方案:添加输入验证和调试输出(如打印变量值)。

3. 多条件判断逻辑混乱

原因:复杂的条件组合(如同时判断行和列的多个边界)容易出错。
解决方案:将条件拆分为多个独立判断,或使用布尔变量暂存中间结果:

boolean isEdge = (i == 0) || (i == lastRow) || (j == 0) || (j == lastCol);  
if(isEdge) { ... }  

应用场景与拓展思考

1. 图形界面编程

在Swing或JavaFX中,矩形打印的逻辑可转化为图形绘制:

// 假设使用JavaFX的Canvas  
canvas.getGraphicsContext2D().fillRect(x, y, width, height);  

2. 游戏开发中的地图生成

矩形打印的二维数组思维可扩展为游戏地图:

// 简化版地图数据  
char[][] gameMap = new char[20][20]; // 20x20的地图  
// 初始化围墙  
for(int i=0; i<20; i++) {  
    gameMap[0][i] = '#'; // 上边界  
    gameMap[19][i] = '#'; // 下边界  
}  

3. 日志格式化与数据可视化

在日志系统中,矩形打印的技巧可用于生成结构化的输出:

// 打印表格标题行  
System.out.println("┌──────────┬──────────┐");  
System.out.println("| 列1       | 列2       |");  
System.out.println("├──────────┼──────────┤");  
// 数据行循环  
for(...) {  
    System.out.printf("| %-8s | %-8s |\n", data1, data2);  
}  
System.out.println("└──────────┴──────────┘");  

结论

通过本文的讲解,我们不仅掌握了"Java 实例 – 打印矩形"的核心逻辑,还探索了其在动态参数处理、性能优化、图形界面等领域的应用。矩形打印看似简单,实则蕴含了循环控制、条件判断、数据结构等编程基础的精华。对于初学者而言,建议通过修改参数值、尝试不同字符图案(如#@)或添加颜色效果,逐步提升代码的复杂度。对于中级开发者,可以思考如何将二维数组扩展为三维空间数据结构,或结合算法实现矩形的动态生成与动画效果。编程是一门实践的艺术,愿各位读者在不断尝试中收获乐趣与成长!


(全文共约 2300 字)

最新发布