Java语言基础(SE)-第九节 GUI、jar包、文档、网络编程

GUI(Graphical User Interface)

  1. GUI(Graphical User Interface):图形用户界面
    1. 指在计算机中采用图形方式显示的用户界面
  2. 1970年代,美国施乐公司的研究人员开发出了第一个图形用户界面,这一设计使得计算机实现了字符界面向图形界面的转变,后来,微软、苹果等公司的操作系统陆续出现,界面设计不断完善,现在日常生活中使用的操作系统、应用程序都是基于 GUI 的

Java 的 GUI 编程方案

  1. Java 也可以开发 GUI 程序,常见的实现方案有 4 种
    1. AWT(Abstract Window Toolkit):Java 官方最早推出的 GUI 编程开发包,界面风格是跟随操作系统的
    2. SWT(Standard Widget Toolkit):由 IBM 推出,著名的开发工具 Eclipse 就是用 SWT 开发的
    3. Swing:在 AWT 的基础上扩充了功能,灵活且强大,在不同操作系统中可以保持统一风格
    4. JavaFX:Java 官方推出的最新一代 GUI 编程开发包,参考资料要比 Swing 少一些
  2. 就是用Java语言开发PC的客户端应用程序

Swing 的常用组件

  1. Swing 提供了一套丰富多彩的组件,下图仅列出了几个常用组件
    1. 紫色的在 java.awt 包中,绿色的在 javax.swing 包中

    图1

  2. Swing 组件预览
    1. JLabel/JButton/JTextField/JPassworkField/JDialog/JTextArea/JCheckBox/JList
  3. 代码举例:

     package com.zh;
     import java.awt.FlowLayout;
     import java.awt.Font;
     import javax.swing.JButton;
     import javax.swing.JDialog;
     import javax.swing.JFrame;
     import javax.swing.JLabel;
     import javax.swing.JTextField;
        
     @SuppressWarnings("serial")
     public class Myframe extends JFrame {
         public Myframe() {
         super("我是一个窗口");
         setBounds(300,100,400,400);
         //点击窗口右上角的x退出应用程序
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         //设置流水布局,水平、竖直间距为20
         setLayout(new FlowLayout(FlowLayout.LEFT,20,20));
            	
         //文本
         Font font = new Font("微软雅黑",Font.PLAIN,18);
            	
         //输入框
         JTextField txf1 = new JTextField(5);
         txf1.setFont(font);
         add(txf1);
            	
         JLabel addLabel = new JLabel("+");
         addLabel.setFont(font);
         add(addLabel);
            	
         //输入框
         JTextField txf2 = new JTextField(5);
         txf2.setFont(font);
         add(txf2);
            	
         JLabel addLabel2 = new JLabel("=");
         addLabel2.setFont(font);
         add(addLabel2);
         JLabel resultLabel = new JLabel("?");
         resultLabel.setFont(font);
         add(resultLabel);
            	
         //按钮
         JButton btn = new JButton("计算");
         btn.setFont(font);
         //监听事件点击
         btn.addActionListener((evt)->{
             try {
                 int num1 = Integer.parseInt(txf1.getText());
                 int num2 = Integer.parseInt(txf2.getText());
                 resultLabel.setText(num1 + num2 + "");
             } catch (Exception e) {
                 int w =300;
                 int h = 100;
                 int x = getX() + ((getWidth()-w)>>1);
                 int y = getY() + ((getHeight()-h)>>1);
                 JDialog dialog = new JDialog(this,true);
                 dialog.setTitle("警告");
                 dialog.setBounds(x,y,w,h);
                 JLabel label = new JLabel();
                 label.setText("请输入整数!!!");
                 label.setFont(font);
                 dialog.add(label);
                 dialog.setResizable(false);
                 dialog.setVisible(true);
             }
         });
             add(btn);
         }
     }
        
     public static void main(String[] args) {
         //创建一个窗口
         Myframe frame = new Myframe();
         frame.setVisible(true);
     }
     public void test1() throws Exception {
         //创建一个窗口
         JFrame frame = new JFrame("我是一个窗口");
         frame.setBounds(300,100,200,200);
         //点击窗口右上角的x退出应用程序
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         //显示窗口
         frame.setVisible(true);
     }
    

Java 程序的运行过程

  1. 思考:Eclipse 是如何将我们开发的 Java 程序运行起来的?

       源代码     编译        字节码      加载         解析
     .java 文件   ->       .class 文件   ->    JVM   ->    机器指令
    
  2. JDK 的 bin 目录中已经包含了运行 Java 程序的必备工具(.exe文件)(Eclipse 就是调用了这些工具将 Java 程序运行起来的)

    1. javac.exe 文件
      1. 编译 xx.java 文件为 xx.class 文件
      2. 举例使用
        1. 创建一个test.java文件,里面写上代码
        2. 然后命令行使用javac main.java,会生成一个main.class文件
        3. 注意:因为windows中已经配置过path,所以这里执行javac命令不需要cd到bin目录
    2. java.exe 文件 xx
      1. 启动 JVM,加载 xx.class 文件
      2. 命令行执行:java main,会自动执行main.class文件中的代码

.class 文件

  1. 每一个类(也包括枚举)、接口编译完毕后都会生成一个对应的 .class 文件

     类型                   .class 文件名
     顶级类型(类、接口)      类型
     嵌套类型(类、接口)      外部类型 + $ + 嵌套类型
     局部类                  外部类型 + $ + 数字 + 局部类
     匿名类                  外部类型 + $ + 数字
    

main 方法的参数

public class Main {

    public static void main(String[] args) {
        try {
            int n1 = Integer.parseInt(args[0]);
            int n2 = Integer.parseInt(args[1]);
            System.out.format("%d + %d  = %dn",n1, n2,n1+n2);
        } catch (Exception e) {
            System.out.println("Please pass two ints.");
        }
    }
}
  1. 通过命令行执行javac Main.java,生成Main.class
  2. 执行java Main,则:Please pass two ints.
    1. 因为并没有传参,args为null,所以报错
  3. 执行java Main 11 22 则: 11 + 22 = 33
  4. 综上,main函数参数就是启动main方法时,传递的参数

main 方法的限制

  1. 必须是公共、静态(public、static)
  2. 不能有返回值(void )
  3. 有且只有 1 个参数,参数类型只能是String[]或者String…

JAR包

  1. 如果想将自己写的 Java 代码提供给其他人使用,常见做法有
    1. 开源分享:将相关的 .java 文件直接分享出去
    2. 闭源分享:将相关的 .class 文件打包成一个 .jar 文件后分享出去
  2. JAR,全称是 Java Archive,使用 ZIP 文件格式来打包
  3. Eclipse 自带了导出 JAR 包的功能:右击项目名称 → Export → Java → JAR File
    1. 本质上是调用了 JDK bin 目录中的jar.exe工具
    2. 选择你打包的java文件
    3. 选择导出的路径和导出的文件名,比如:Untitled.jar
    4. 点击finish
    5. 会生成一个jar包,里面其实是.class文件
    6. 注意: 这个页面中的打钩选项是Export generated class files and resources
  4. 可以对 JAR 进行数字签名,防止代码被篡改
  5. 如何引入别人的jar包?
    1. 在src同级目录下新建一个libs文件夹
    2. 将第三方的jar包复制进去
    3. 右击jar包,Build Path -> Add to Build Path
    4. 此时项目会生成一个Reference Libraries文件夹目,下面而且会有那个jar包
    5. 这样才算是这个项目正式引用了那个jar包
  6. 如何将源代码(java)打成jar包而且和非源码一起共存呢?
    1. 将第三步的的勾选为:Export Java source files and resources,导出文件名加个.sources,即Untitled.sources.jar
      1. 这个jar包内部包含的是java源码文件
    2. 将Untitled.sources.jar文件复制到项目libs中
    3. 右击之前引入非源码生成的Reference Libraries文件夹下的Untitled.jar包
    4. 点击properties->Java Source Arrachment->选择文件路径,选择libs文件夹下的Untitled.sources.jar文件,点击OK即可
    5. 这样Untitled.jar中的API就与Untitled.sources.jar做了关联,点击方法就可以查看源代码了
      1. 源代码只能查看不能修改

Runnable JAR

  1. 可运行 JAR(Runnable JAR):包含了程序入口 main 方法的 JAR
    1. 就相当于导出一个exe,别人直接可以运行
  2. 操作步骤
    1. 右击项目名称 → Export → Java → Runnable JAR File->next
    2. 选择入口Launch configuration: 选择你这个项目的main入口
    3. 选择导出路径Export destination,以及文件名命名,比如swing.jar
    4. Library handing(所依赖的第三方库的处理方式)
      1. Extract required libraries into generated JAR
        1. 将第三方库的内容解压后放入 JAR 中 (默认使用这个即可)
      2. Package required libraries into generated JAR
        1. 第三方库不解压,直接放入 JAR 中
      3. Copy required libraries into a sub-folder next to the generated JAR
        1. 将第三方库放入跟 JAR 同目录的文件夹中(文件夹名默认是:JAR文件名_lib)
    5. 点击保存,完成
    6. 双击swing.jar,就可以运行程序了(前提是安装了java运行环境JDK)
  3. 启动 Runnable JAR 的常见方式
    1. 命令行
      1. java –jar JAR文件路径
    2. 编写 bat 脚本文件,双击执行 bat 文件(适用于 Windows)
      1. bat 文件的内容大概如下所示

         java –jar JAR文件路径 
         pause
        
    3. 利用工具将 JAR 转为 exe 文件,双击执行 exe 文件(适用于 Windows,依然需要 JVM 的支持)
      1. 比如 exe4j :https://exe4j.apponic.com/download/

生成 Java 文档

  1. 开发完一个jar包,给别人提供一个使用文档
  2. 在代码中要使用文档注释,才会对应生成
  3. 生成步骤
    1. 点击顶部工具栏project->Generate JavaDoc
    2. 选择要生成的项目
    3. 选择public
    4. 选择生成文档的路径
    5. 点击next,继续点击next
    6. 输入文档的编码格式VM options下输入:-encoding UTF-8 -charset UTF-8
    7. 点击finish
    8. 双击doc文件中的index就可以看内容

双括号初始化(Double Brace Initialization)

  1. 举例

     List<Integer> list = new ArrayList<Integer>() *{
         add(11);
         add(22);
     }};
     //[11, 22]
     System.out.println(list);
    
  2. 特点:任何对象都可以用双括号初始化,在双括号内部使用该对象的成员方法
  3. 优缺点
    1. 优点: 代码简洁
    2. 缺点:本质是多生成了一个匿名类、可能会影响 equals 方法的正常使用
  4. 建议:慎重使用

网络编程

  1. 在 Java 中,使用 java.net.Socket、java.net.ServerSocket 可以实现 TCP 请求
  2. 在 Java 中,使用 java.net.DatagramSocket 可以实现 UDP 请求
  3. 代码示例
    1. 客户端代码:

       package com.zh;
       import java.io.ByteArrayOutputStream;
       import java.io.InputStream;
       import java.io.OutputStream;
       import java.net.Socket;
       //客户端
       public class TCPClient {
           public static void main(String[] args) throws Exception {
               //参数为要请求的服务器地址、端口
               Socket socket = new Socket("127.0.0.1",8888);
               //输出流,客户端给服务器输出
               OutputStream os = socket.getOutputStream();
               //输入流,服务器输入到客户端
               InputStream  isinput = socket.getInputStream();
               //字节数组输出流,收集服务端发过来的数据
               ByteArrayOutputStream baos = new ByteArrayOutputStream();
               //向服务器写数据
               os.write("66667".getBytes("UTF-8"));
               //关闭输出,表面写给服务器的数据写完了
               socket.shutdownOutput();
                      	
               //读取服务器发送的数据
               byte[] buffer = new byte[8192];
               int len;
               //每读取到一次,写一次
               while ((len = isinput.read(buffer))!= -1) {
                   baos.write(buffer,0,len);
               }
               //所有收到的数据
               byte[] bytes =  baos.toByteArray(); 
               String content = new String(bytes,"UTF-8");
               System.out.format("客户端接收到的数据:%s%n",content);
               //给服务器发送完毕,就关闭请求
               os.close();
               socket.close();
           }
       }
      
    2. 服务器代码

       package com.zh;
       //服务端
       import java.io.ByteArrayOutputStream;
       import java.io.IOException;
       import java.io.InputStream;
       import java.io.OutputStream;
       import java.net.ServerSocket;
       import java.net.Socket;
       public class TCPServer {
           public static void main(String[] args) throws Exception {
               try (ServerSocket serverScoket = new ServerSocket(8888)){
                   //让服务器一直监听
                   while (true) {
                       //监听客户端的请求,客户端一旦发送请求,就会生成一个socket对象
                       Socket client = serverScoket.accept();
                       //开启新线程执行
                       new Thread(()->{
                           try {
                               doClient(client);
                               client.close();
                           } catch (Exception e) {
                               e.printStackTrace();
                           }
                       }).start();
                   }
               }
           }
           static void doClient(Socket client) throws IOException {
               try(
                   //字节数组输出流,收集客户端发过来的数据
                   ByteArrayOutputStream baos = new ByteArrayOutputStream();
                   //输入流:客户端输入给服务器
                   InputStream isinput =  client.getInputStream();
                   //输出流,服务器输出给客户端
                   OutputStream os = client.getOutputStream();
               ){
                   //读取客户端的数据
                   byte[] buffer = new byte[8192];
                   int len;
                   //每读取到一次,写一次
                   while ((len = isinput.read(buffer))!= -1) {
                       baos.write(buffer,0,len);
                   }
                   //所有收到的数据
                   byte[] bytes =  baos.toByteArray(); 
                   String content = new String(bytes,"UTF-8");
                   //获取到客户端的IP地址
                   String ip = client.getInetAddress().getHostAddress();
                   System.out.format("服务器接收到[%s]的数据:%s%n",ip,content);
                   //写数据给客户端
                   os.write(doString("你吃饭了么?").getBytes("UTF-8"));
               }
           }
                  	
           static String doString(String str){
           str = str.replace("你", "朕");
           str = str.replace("吗", "");
           str = str.replace("么", "");
           str = str.replace("?", "!");
           return str.replace("?", "!");
       }
      

Java 实现网络爬虫

  1. 有个叫做 jsoup 的 Java 第三方库,可以用来编写基本的网络爬虫程序
    1. https://jsoup.org/
  2. 下载jar包,然后导入到项目

     //参数为要抓取的网页地址
     Document doc = Jsoup.connect("https://en.wikipedia.org/").get();
     log(doc.title());
     //查找指定的元素
     Elements newsHeadlines = doc.select("#mp-itn b a");
     for (Element headline : newsHeadlines) {
         log("%s\n\t%s", 
         headline.attr("title"), headline.absUrl("href"));
     }
    
Table of Contents