• Swing程序设计详解(一)


    【今日】

    “若你决定灿烂,山无遮,海无拦” 
     

    目录

     初识Swing

    一   Swing简述 

    二  Swing常用窗体 

    2.1 JFrame窗体

    2.2 JDialog对话框

    2.3JOptionPane小型对话框

    (1)通知框

    (2)确认框

    (3)输入框 

    (4)自定义对话框

     三   常用布局管理器 

    3.1 绝对布局 

    3.2 流布局 

    3.3 边界布局

    3.4 网格布局 

    四   常用面板

    4.1 JPanel面板

     

    4.2 JScrollpane滚动面板



     初识Swing



           Swing用于开发桌面窗体程序,是JDK的第二代GUI框架,其功能比JDK第一代GUI框架AWT更为强大、性能更加优良。但因为Swing技术推出时间太早,其性能、开发效率等不及一些其他流行技术,所以目前市场上大多数桌面窗体程序都不是由Java开发的,Swing技术也逐渐被广大开发人员放弃了。
           不过,Swing是JDK自带的功能,并且能非常好地体现Java语言在面向对象、接口事件等方面的设计模式,又能提供直观地呈现运行效果。
           Swing中的大多数组件均为轻量级组件,使用Swing开发出的窗体风格会与当前平台(如Windows、Linux等)的窗体风格保持一致。



    一   Swing简述 

           Swing主要用来开发GUI(Graphical User Interface)程序,GUI是应用程序提供给用户操作的图形界面,包括窗口、菜单、按钮等图形界面元素,我们经常使用的QQ软件、360安全卫士等均为GUI程序。Java语言为Swing程序的开发提供了丰富的类库,这些类分别被存储在java.awt和javax.swing包中。Swing提供了丰富的组件,在开发Swing程序时,这些组件被广泛地应用。

           Swing组件是完全由Java语言编写的组件。因为Java语言不依赖于本地平台(即“操作系统”),所以Swing组件可以被应用于任何平台。基于“跨平台”这一特性,Swing组件被称作“轻量级组件”;反之,依赖于本地平台的组件被称作“重量级组件”,在Swing包的层次结构和继承关系中,比较重要的类是Component类(组件类)、Container类(容器类)和JComponent类(Swing组件父类)。Swing包的层次结构和继承关系如图所示。

    常用的Swing组件



    二  Swing常用窗体 

    2.1 JFrame窗体

           开发Swing程序的流程可以被简单地概括为首先通过继承javax.swing.JFrame类创建一个窗体,然后向这个窗体中添加组件,最后为添加的组件设置监听事件。

    JFrame类的常用构造方法包括以下两种形式:
    public JFrame():创建一个初始不可见、没有标题的窗体
    public JFrame(String title):创建一个不可见、具有标题的窗体

    比如:创建一个不可见有标题的窗体;

    1. JFrame f = new JFrame("窗体标题");//创建窗体对象
    2. Container c = f.getContentPane();//获取窗体容器

    在创建窗体后,先调用getContentPane()方法将窗体转换为容器,再调用add(方法或者remove()方法向容器中添加组件或者删除容器中的组件。向容器中添加按钮,关键代码如下:

    1. JLabel l= new JLabel("这是一个窗体");//创建了一个标签
    2. c.add(l);//添加组件
    3. c.remove(l);//删除组件

    创建窗体后,要对窗体进行设置,如设置窗体的位置、大小、是否可见等。JFrame类提供的相应方法可实现上述设置操作,具体如下:

    1. setBounds(int x, int y, int width, int leight):设置窗体左上角在屏幕中的坐标为(x,y),窗体的宽
    2. 度为width,窗体的高度为height。
    3. setLocation(int x,int y):设置窗体左上角在屏幕中的坐标为(x,y)。
    4. setSize(int width, int height):设置窗体的宽度为width,高度为height。
    5. setVisibale(boolean b):设置窗体是否可见。b为true时,表示可见;b为false时,表示不可见。

    JFrame窗体关闭的几种方式

    下面我们用代码来实现一个窗体程序:

    【代码实列】

    1. import java.awt.Color;
    2. import java.awt.Container;
    3. import javax.swing.JFrame;
    4. import javax.swing.JLabel;
    5. public class Demo {
    6. public static void main(String[] args) {
    7. JFrame f = new JFrame("窗体标题");//创建窗体对象
    8. f.setVisible(true);//设置窗体可见
    9. /*
    10. * 窗体关闭规则
    11. * EXIT_ON_CLOSE:隐藏窗体,并停止程序
    12. * DO_NOTHING_ON_CLOSE:无任何操作
    13. * HIDE ON_ CLOSE:隐藏窗体,但不停止程序
    14. * DISPOSE_ ON_CLOSE:释放窗体资源
    15. */
    16. f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    17. f.setSize(300, 200);//设置窗体的大小,单位:像素
    18. f.setLocation(400, 300);//设置窗体的位置,单位:像素
    19. /*
    20. * f.setBounds(x, y, 长, 高);//可以用一句代替上面的两句
    21. */
    22. Container c = f.getContentPane();//获取窗体容器
    23. c.setBackground(Color.WHITE);//设置背景颜色
    24. JLabel l= new JLabel("这是一个窗体");//创建了一个标签
    25. c.add(l);//添加组件
    26. // c.remove(l);//删除组件
    27. c.validate();//验证容器中的组件(相当于刷新操作)
    28. // f.setContentPane(c);重新载入容器(相当于刷新操作)
    29. f.setResizable(false);//设置窗体是否可以改变大小
    30. System.out.println("窗体的位置:x="+f.getX()+" y="+f.getY());
    31. }
    32. }

    【运行结果】 

    但在实际中我们一般会直接继承JFrame,不在单独创建对象,初学者可以先了解一下:

    1. import java.awt.Color;
    2. import java.awt.Container;
    3. import javax.swing.JFrame;
    4. import javax.swing.JLabel;
    5. public class Demo extends JFrame{//让Demo类也成为一个窗体
    6. public Demo(){
    7. setVisible(true);//设置窗体可见
    8. setTitle("窗口标题");
    9. /*
    10. * 窗体关闭规则
    11. * EXIT_ON_CLOSE:隐藏窗体,并停止程序
    12. * DO_NOTHING_ON_CLOSE:无任何操作
    13. * HIDE ON_ CLOSE:隐藏窗体,但不停止程序
    14. * DISPOSE_ ON_CLOSE:释放窗体资源
    15. */
    16. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    17. setSize(300, 200);//设置窗体的大小,单位:像素
    18. setLocation(400, 300);//设置窗体的位置,单位:像素
    19. /*
    20. * f.setBounds(x, y, 长, 高);//可以用一句代替上面的两句
    21. */
    22. Container c = getContentPane();//获取窗体容器
    23. c.setBackground(Color.WHITE);//设置背景颜色
    24. JLabel l= new JLabel("这是一个窗体");//创建了一个标签
    25. c.add(l);//添加组件
    26. // c.remove(l);//删除组件
    27. c.validate();//验证容器中的组件(相当于刷新操作)
    28. // setContentPane(c);重新载入容器(相当于刷新操作)
    29. setResizable(false);//设置窗体是否可以改变大小
    30. System.out.println("窗体的位置:x="+getX()+" y="+getY());
    31. }
    32. public static void main(String[] args) {
    33. new Demo();
    34. }
    35. }

    2.2 JDialog对话框

           Dialog对话框继承了java.awt.Dialog类,其功能是从一个窗体 中弹出另一个窗体,如使用IE浏览器时弹出的确定对话框。JDialog对话框与JFrame窗体类似,被使用时也需要先调用getContentPane()方法把JDialog对话框转换为容器,再对JDialog对话框进行设置。

    public JDialog():创建一个没有标题和父窗体的对话框。
    public JDialog(Frame f):创建一个没有标题,但指定父窗体的对话框。
    public JDialog(Frame f, boolean model):创建一个没有标题,但指定父窗体和模式的对话框。如果model为true,那么弹出对话框后,用户无法操作父窗体。
    public JDialog(Frame f, String title):创建一个指定标题和父窗体的对话框。
    public JDialog(Frame f, String title, boolean model):创建一个指定标题、父窗体和模式的对话框。

    【代码实列】

    1. import java.awt.Container;
    2. import java.awt.FlowLayout;
    3. import java.awt.event.ActionEvent;
    4. import java.awt.event.ActionListener;
    5. import javax.swing.*;
    6. public class Demo extends JDialog{
    7. public Demo(JFrame frame) {
    8. /*
    9. * 第一个参数是父窗体对象
    10. * 第二个参数是对话框标题
    11. * 第三个参数是是否阻塞父窗体
    12. * true为阻塞,false为不阻塞
    13. */
    14. super(frame, "对话框标题", true);
    15. //第一个传入frame对象(父窗体)
    16. Container c = getContentPane();//获取窗体容器
    17. c.add(new JLabel("这是一个窗体对话框"));
    18. setBounds(100, 100, 100, 100);
    19. }
    20. public static void main(String[] args) {
    21. JFrame f =new JFrame("父窗体");
    22. f.setBounds(50, 50, 300, 300);
    23. Container c = f.getContentPane();
    24. JButton btn = new JButton("弹出对话框");//设置一个按钮
    25. c.setLayout(new FlowLayout());//设置布局,使用流布局
    26. c.add(btn);
    27. f.setVisible(true);
    28. f.setDefaultCloseOperation(EXIT_ON_CLOSE);
    29. btn.addActionListener(new ActionListener() {
    30. //创建了一个匿名对象
    31. @Override
    32. public void actionPerformed(ActionEvent e) {
    33. // 这个方法就是点击按钮以后会运行的方法
    34. Demo d =new Demo(f);
    35. d.setVisible(true);//设置窗体可见
    36. }
    37. });//添加动作监听
    38. }
    39. }

    【运行效果】



    2.3JOptionPane小型对话框

         Java API中的javax.swing.JOptionPane类是一个非常简便的小型对话框类,该类用于创建对话框的方法都是静态方法,无须创建对象即可弹出。在日常开发中经常使用该类弹出提示、确认用户需求、调试程序等。JOptionPane提供了4种创建对话框的方法 ,如表所示:


    (1)通知框

           通知框是最简单的一个对话框,仅弹出提示,不会返回任何值。

    1.样式:

    2.创建通知框的代码块:

    1. showMessageDialog(Component parentComponent,//在那个窗口弹出
    2. object message, //通知什么内容
    3. String title, //标题
    4. int message Type) //通知框的风格

    3.通知框的风格:

    【代码实列】

    1. import javax.swing.JOptionPane;
    2. public class Demo {
    3. public static void main(String[] args) {
    4. JOptionPane.showMessageDialog(null,
    5. "您与服务器断开连接",
    6. "发生错误",
    7. JOptionPane.WARNING_MESSAGE);
    8. }
    9. }

    【运行效果】

    WARNING_MESSAGE:

    WARNING_MESSAGE:


    (2)确认框

           确认框已经封装好了一套外观样式,弹出后要求用户做选择操作,用户选择具体选项后,确认框可以返回用户的选择结果,结果以int方式返回。

    1.样式:

    2.创建确认框的代码块:

    1. showConfirmDialog(Component parentComponent,//在那个窗口弹出
    2. object message, //通知什么内容
    3. String title, //标题
    4. int message Type) //通知框的风格

    3.通知框的风格:

    YES_NO_CANCEL_OPTION:3键

    YES_NO_OPTION:2键

    【代码实列】

    1. import javax.swing.JOptionPane;
    2. public class Demo {
    3. public static void main(String[] args) {
    4. JOptionPane.showConfirmDialog(null,
    5. "确定离开吗?",
    6. "提示",
    7. JOptionPane.YES_NO_CANCEL_OPTION);
    8. }
    9. }

    【运行效果】

    YES_NO_CANCEL_OPTION:

    YES_NO_OPTION:

    因为该确认窗可以返回结果,所以我们可以通过结果判断用户的选择:

    是:0  否:1  X:-1   取消:2


    (3)输入框 

    输入框已经封装好了一套外观样式,弹出后要求用户在文本框中输入文本,用户完成输入操作后,
    输入框可以返回用户输入的结果.

    1.样式:

    2.创建输入框的代码块:

    1. showInputDialog(Component parentComponent, //在那个窗口弹出
    2. Object message, //通知什么内容
    3. String title, //标题
    4. int messageType) //输入框的风格

    【代码实列】

    1. import javax.swing.JOptionPane;
    2. public class Demo {
    3. public static void main(String[] args) {
    4. String name =JOptionPane.showInputDialog(null,
    5. "请输入你的姓名");
    6. System.out.println(name);
    7. }
    8. }

    【运行效果】


    (4)自定义对话框

    自定义对话框模板:

    1. showOptionDialog(Component parentComponent,//在哪个窗体弹出
    2. Object message, //通知什么内容?
    3. String title, //标题
    4. int optionType, //选项类型,可定义按钮风格
    5. int messageType, //消息类型,可定义外观风格
    6. Icon icon, //图标
    7. Object[] options, //有哪些组件
    8. Object initialValue) //默认选中的组件

    在下面自定义中我们会用到这个图标:

    【代码实列】

    1. import javax.swing.Icon;
    2. import javax.swing.ImageIcon;
    3. import javax.swing.JButton;
    4. import javax.swing.JOptionPane;
    5. public class Demo {
    6. public static void main(String[] args) {
    7. Icon icon = new ImageIcon("src/注意.png");//获得图标
    8. JButton b1 = new JButton("是的");//创建组件按钮b1
    9. JButton b2 = new JButton("再想想");//创建组件按钮b2
    10. Object os[] = {b1,b2};
    11. JOptionPane.showOptionDialog(null,
    12. "你准备好了吗?",
    13. "注意了",
    14. JOptionPane.DEFAULT_OPTION,
    15. JOptionPane.DEFAULT_OPTION,
    16. icon,
    17. os,
    18. null);
    19. }
    20. }

    【运行效果】



     三   常用布局管理器 

          开发Swing程序时,在容器中使用布局管理器能够设置窗体的布局,进而控制Swing组件的位置大小。Swing 常用的布局管理器为绝对布局管理器、流布局管理器、边界布局管理器和网格布局管器。


    3.1 绝对布局 

    绝对布局也叫null布局,其特点是硬性指定组件在容器中的位置和大小,组件的位直通过绝对坐 标的方式来指定。使用绝对布局首先要使用Container.setLayout(null)方法取消容器的布局管理器,然后再使用Component.setBounds(int x,int y,int width, int height)方法设置每个组件在容器中的位置和大小。

    【实列代码】

    1. import java.awt.Container;
    2. import javax.swing.*;
    3. public class Demo extends JFrame{
    4. public Demo() {
    5. setTitle("标题");//设置标题
    6. setBounds(100, 300,800, 400);//设置位置以及大小
    7. setVisible(true);//设置窗体是否可见
    8. setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭方式
    9. Container c = getContentPane();//设置容器
    10. c.setLayout(null);//设置为null布局
    11. JButton b1 = new JButton("按钮1");//设置按钮
    12. JButton b2 = new JButton("按钮2");
    13. b1.setBounds(10, 20, 100, 50);
    14. b2.setBounds(400, 20, 100, 50);
    15. c.add(b1);
    16. c.add(b2);
    17. }
    18. public static void main(String[] args) {
    19. Demo d = new Demo();
    20. }
    21. }

     【运行结果】

     注意:

    绝对布局不具备弹性,页面元素的位置和尺寸无法基于内容或用户需求进行自适应调整。这可能导致在内容不同或窗口大小变化时产生剪切、溢出或显示问题。绝对布局里面的按钮位置不会因为窗体的大小改变位置而发生改变,如图所示:


    3.2 流布局 

    流布局(FlowLayout)管理器是Swing中最基本的布局管理器。使用流布局管理器摆放组件时,组件被从左到右摆放。当组件占据了当前行的所有空间时,溢出的组件会被移动到当前行的下一行。默认情况下,行组件的排列方式被指定为居中对齐,但是通过设置可以更改每一行组件的排列方式。

    FlowLayout的三种构造方法:
    FloyLayout();           // 默认构造方法

    FloyLayout(int alignment);  //

    FloyLayout(int alignment int horizGap,int vertGap);

    //对齐方式   水平间距   垂直间距

    对齐方式:
    FlowLayout.LEFT        //左对齐

    FlowLayout.RIGHT     //右对齐

    FlowLayout.CENTER //居中对齐

    【代码实列】 

    1. import java.awt.Container;
    2. import java.awt.FlowLayout;
    3. import javax.swing.*;
    4. public class Demo extends JFrame{
    5. public Demo() {
    6. setTitle("标题");//设置标题
    7. setBounds(100,100,300,200);//设置位置以及大小
    8. setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭方式
    9. Container c = getContentPane();//设置容器
    10. c.setLayout(new FlowLayout());//设置为流布局
    11. for(int i=0;i<=9;i++) {
    12. c.add(new JButton("按钮"+i));
    13. }
    14. setVisible(true);//设置窗体是否可见
    15. }
    16. public static void main(String[] args) {
    17. Demo d = new Demo();
    18. }
    19. }

     【运行结果】

    当窗口调节时:按钮位置也会随之变化: 

    但时如果窗体大小太小,它没有最合理的分配方法,此时会丢失部分按钮:


    3.3 边界布局

    使用 Swing创建窗体后,容器默认的布局管理器是边界布局(BorderLayout)管理器,边界布局管理器把容器划分为东、南、西、北、中5个区域,如图所示。


    当组件被添加到被设置为边界布局管理器的容器时,需要使用BorderLayout类中的成员变量指定被添加的组件在边界布局管理器中的区域,BorderLayout类中的成员变量及其说明如下表:

    【代码实列】

    1. import java.awt.BorderLayout;
    2. import java.awt.Container;
    3. import javax.swing.*;
    4. public class Demo extends JFrame{
    5. public Demo() {
    6. setTitle("边界布局");//设置标题
    7. setBounds(100,100,300,200);//设置位置以及大小
    8. setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭方式
    9. Container c = getContentPane();//设置容器
    10. c.setLayout(new BorderLayout());//设置为边界布局
    11. JButton b1 = new JButton("中");
    12. JButton b2 = new JButton("东");
    13. JButton b3 = new JButton("西");
    14. JButton b4 = new JButton("南");
    15. JButton b5 = new JButton("北");
    16. c.add(b1, BorderLayout.CENTER);
    17. c.add(b2, BorderLayout.EAST);
    18. c.add(b3, BorderLayout.WEST);
    19. c.add(b4, BorderLayout.SOUTH);
    20. c.add(b5, BorderLayout.NORTH);
    21. setVisible(true);//设置窗体是否可见
    22. }
    23. public static void main(String[] args) {
    24. Demo d = new Demo();
    25. }
    26. }

     【运行结果】

    注意:

    在同一个区域反复添加元素时,新元素会覆盖旧元素。当窗体长足够小是,只有南北按钮。 


    3.4 网格布局 

    网格布局(GridLayout)管理器能够把容器划分为网格,组件可以按行、列进行排列。在网格布局管理器中,网格的个数由行数和列数决定,且每个网格的大小都相同。例如,一个两行两列的网格布局管理器能够产生4个大小相等的网格。组件从网格的左上角开始,按照从左到右、从上到下的顺序被添加到网格中,且每个组件都会填满整个网格。改变窗体大小时,组件的大小也会随之改变。

    两种构造方法:

    【代码实列】

    1. import java.awt.Container;
    2. import java.awt.GridLayout;
    3. import javax.swing.*;
    4. public class Demo extends JFrame{
    5. public Demo() {
    6. setTitle("网格布局");//设置标题
    7. setBounds(100,100,300,300);//设置位置以及大小
    8. setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭方式
    9. Container c = getContentPane();//设置容器
    10. c.setLayout(new GridLayout(4,5));//
    11. for(int i=0;i<20;i++) {
    12. c.add(new JButton("按钮"+i));
    13. }
    14. setVisible(true);//设置窗体是否可见
    15. }
    16. public static void main(String[] args) {
    17. Demo d = new Demo();
    18. }
    19. }

     【运行结果】

    四   常用面板

     在Swing程序设计中,面板是一个容器,背用于容纳其他组件,但面板必须被添加到其他容器中。


    4.1 JPanel面板

    Jpanel面板继承java.awt.Container类。JPanel面板必须在窗体容器中使用,无法脱离窗体显示。

    初始化一个面板的方法:

    Jpanel p = new JPanel(new 布局方法);

    使用JPanel可以将其他Swing组件添加到其中。使用JPanel的setLayout()方法可以设置布局管理器来控制组件在面板中的放置方式。

    【代码实列】

    1. import java.awt.BorderLayout;
    2. import java.awt.Container;
    3. import java.awt.GridLayout;
    4. import javax.swing.*;
    5. public class Demo extends JFrame{
    6. public Demo() {
    7. setTitle("面板");//设置标题
    8. setBounds(100,100,500,300);//设置位置以及大小
    9. setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭方式
    10. Container c = getContentPane();//获得一个容器
    11. c.setLayout(new GridLayout(2,2,10,10));//设置布局
    12. JPanel p1 = new JPanel();//设置布局
    13. p1.setLayout(new GridLayout(1,3,10,10));//面板设置为网格布局
    14. JPanel p2= new JPanel(new BorderLayout());//面板设置为边界布局
    15. JPanel p3 = new JPanel(new GridLayout(1,2,10,10));
    16. JPanel p4 = new JPanel(new GridLayout(2,1,10,10));
    17. /*
    18. * 给每个面板添加边框和标题,使用BorderFactory工厂类生成带标题的
    19. * 边框对象
    20. */
    21. p1.setBorder(BorderFactory.createTitledBorder("面板一"));//添加标题边框
    22. p2.setBorder(BorderFactory.createTitledBorder("面板二"));
    23. p3.setBorder(BorderFactory.createTitledBorder("面板三"));
    24. p4.setBorder(BorderFactory.createTitledBorder("面板四"));
    25. /*
    26. * 添加按钮
    27. */
    28. p1.add(new JButton("P1"));
    29. p1.add(new JButton("P1"));
    30. p1.add(new JButton("P1"));
    31. p1.add(new JButton("P1"));
    32. p2.add(new JButton("P2"), BorderLayout.CENTER);
    33. p2.add(new JButton("P2"), BorderLayout.EAST);
    34. p2.add(new JButton("P2"), BorderLayout.WEST);
    35. p2.add(new JButton("P2"), BorderLayout.NORTH);
    36. p2.add(new JButton("P2"), BorderLayout.SOUTH);
    37. p3.add(new JButton("P3"));
    38. p3.add(new JButton("P3"));
    39. p4.add(new JButton("p4"));
    40. p4.add(new JButton("p4"));
    41. /*
    42. * 将面板添加到容器中
    43. */
    44. c.add(p1);
    45. c.add(p2);
    46. c.add(p3);
    47. c.add(p4);
    48. setVisible(true);//设置窗体可见
    49. }
    50. public static void main(String[] args) {
    51. Demo d = new Demo();
    52. }
    53. }

    【运行结果】


    4.2 JScrollpane滚动面板

    JScrollpane滚动面板是带滚动条的面板,被用于在较小的窗体中显示较大的篇幅的内容。

    【代码实列】

    1. import java.awt.Container;
    2. import javax.swing.*;
    3. public class Demo extends JFrame{
    4. public Demo() {
    5. setBounds(100,100,500,300);//设置位置以及大小
    6. setDefaultCloseOperation(EXIT_ON_CLOSE);//设置窗体关闭的方式
    7. Container c = getContentPane();
    8. JTextArea Jt = new JTextArea();//创建了一个文本域
    9. JScrollPane Js = new JScrollPane(Jt);//创建滚动面板,给文本域添加滚动条
    10. c.add(Js);
    11. setVisible(true);//设置窗体可见
    12. }
    13. public static void main(String[] args) {
    14. new Demo();
    15. }
    16. }

     【运行效果】

  • 相关阅读:
    代码随想录二刷 Day46
    Unity接入微信支付SDK 2022年版安卓篇
    通用场景语音合成数据集推荐
    CPython, Pypy, MicroPython...还在傻傻分不清楚?
    数字集成电路设计(四、Verilog HDL数字逻辑设计方法)(三)
    Golang接口实现OCP原则
    力控关节机器人(关节扭矩传感器力控)
    目标检测YOLO实战应用案例100讲-基于YOLOv7的番茄采摘机械手场景感知及试验(中)
    Proxifier联动BurpSuite抓取小程序
    LeetCode | 使用 “自带栈” 解决中序遍历
  • 原文地址:https://blog.csdn.net/2301_77599154/article/details/132831998