Java语言基础(SE)-第九节 GUI、jar包、文档、网络编程
GUI(Graphical User Interface)
- GUI(Graphical User Interface):图形用户界面
- 指在计算机中采用图形方式显示的用户界面
- 1970年代,美国施乐公司的研究人员开发出了第一个图形用户界面,这一设计使得计算机实现了字符界面向图形界面的转变,后来,微软、苹果等公司的操作系统陆续出现,界面设计不断完善,现在日常生活中使用的操作系统、应用程序都是基于 GUI 的
Java 的 GUI 编程方案
- Java 也可以开发 GUI 程序,常见的实现方案有 4 种
- AWT(Abstract Window Toolkit):Java 官方最早推出的 GUI 编程开发包,界面风格是跟随操作系统的
- SWT(Standard Widget Toolkit):由 IBM 推出,著名的开发工具 Eclipse 就是用 SWT 开发的
- Swing:在 AWT 的基础上扩充了功能,灵活且强大,在不同操作系统中可以保持统一风格
- JavaFX:Java 官方推出的最新一代 GUI 编程开发包,参考资料要比 Swing 少一些
- 就是用Java语言开发PC的客户端应用程序
Swing 的常用组件
- Swing 提供了一套丰富多彩的组件,下图仅列出了几个常用组件
- 紫色的在 java.awt 包中,绿色的在 javax.swing 包中
- Swing 组件预览
- JLabel/JButton/JTextField/JPassworkField/JDialog/JTextArea/JCheckBox/JList
-
代码举例:
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 程序的运行过程
-
思考:Eclipse 是如何将我们开发的 Java 程序运行起来的?
源代码 编译 字节码 加载 解析 .java 文件 -> .class 文件 -> JVM -> 机器指令
-
JDK 的 bin 目录中已经包含了运行 Java 程序的必备工具(.exe文件)(Eclipse 就是调用了这些工具将 Java 程序运行起来的)
- javac.exe 文件
- 编译 xx.java 文件为 xx.class 文件
- 举例使用
- 创建一个test.java文件,里面写上代码
- 然后命令行使用
javac main.java
,会生成一个main.class文件 - 注意:因为windows中已经配置过path,所以这里执行javac命令不需要cd到bin目录
- java.exe 文件 xx
- 启动 JVM,加载 xx.class 文件
- 命令行执行:
java main
,会自动执行main.class文件中的代码
- javac.exe 文件
.class 文件
-
每一个类(也包括枚举)、接口编译完毕后都会生成一个对应的 .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.");
}
}
}
- 通过命令行执行javac Main.java,生成Main.class
- 执行
java Main
,则:Please pass two ints.
- 因为并没有传参,args为null,所以报错
- 执行
java Main 11 22
则:11 + 22 = 33
- 综上,main函数参数就是启动main方法时,传递的参数
main 方法的限制
- 必须是公共、静态(public、static)
- 不能有返回值(void )
- 有且只有 1 个参数,参数类型只能是String[]或者String…
JAR包
- 如果想将自己写的 Java 代码提供给其他人使用,常见做法有
- 开源分享:将相关的 .java 文件直接分享出去
- 闭源分享:将相关的 .class 文件打包成一个 .jar 文件后分享出去
- JAR,全称是 Java Archive,使用 ZIP 文件格式来打包
- Eclipse 自带了导出 JAR 包的功能:右击项目名称 → Export → Java → JAR File
- 本质上是调用了 JDK bin 目录中的jar.exe工具
- 选择你打包的java文件
- 选择导出的路径和导出的文件名,比如:Untitled.jar
- 点击finish
- 会生成一个jar包,里面其实是.class文件
- 注意: 这个页面中的打钩选项是Export generated class files and resources
- 可以对 JAR 进行数字签名,防止代码被篡改
- 如何引入别人的jar包?
- 在src同级目录下新建一个libs文件夹
- 将第三方的jar包复制进去
- 右击jar包,Build Path -> Add to Build Path
- 此时项目会生成一个Reference Libraries文件夹目,下面而且会有那个jar包
- 这样才算是这个项目正式引用了那个jar包
- 如何将源代码(java)打成jar包而且和非源码一起共存呢?
- 将第三步的的勾选为:
Export Java source files and resources
,导出文件名加个.sources,即Untitled.sources.jar- 这个jar包内部包含的是java源码文件
- 将Untitled.sources.jar文件复制到项目libs中
- 右击之前引入非源码生成的Reference Libraries文件夹下的Untitled.jar包
- 点击properties->Java Source Arrachment->选择文件路径,选择libs文件夹下的Untitled.sources.jar文件,点击OK即可
- 这样Untitled.jar中的API就与Untitled.sources.jar做了关联,点击方法就可以查看源代码了
- 源代码只能查看不能修改
- 将第三步的的勾选为:
Runnable JAR
- 可运行 JAR(Runnable JAR):包含了程序入口 main 方法的 JAR
- 就相当于导出一个exe,别人直接可以运行
- 操作步骤
- 右击项目名称 → Export → Java → Runnable JAR File->next
- 选择入口Launch configuration: 选择你这个项目的main入口
- 选择导出路径Export destination,以及文件名命名,比如swing.jar
- Library handing(所依赖的第三方库的处理方式)
- Extract required libraries into generated JAR
- 将第三方库的内容解压后放入 JAR 中 (默认使用这个即可)
- Package required libraries into generated JAR
- 第三方库不解压,直接放入 JAR 中
- Copy required libraries into a sub-folder next to the generated JAR
- 将第三方库放入跟 JAR 同目录的文件夹中(文件夹名默认是:JAR文件名_lib)
- Extract required libraries into generated JAR
- 点击保存,完成
- 双击swing.jar,就可以运行程序了(前提是安装了java运行环境JDK)
- 启动 Runnable JAR 的常见方式
- 命令行
java –jar JAR文件路径
- 编写 bat 脚本文件,双击执行 bat 文件(适用于 Windows)
-
bat 文件的内容大概如下所示
java –jar JAR文件路径 pause
-
- 利用工具将 JAR 转为 exe 文件,双击执行 exe 文件(适用于 Windows,依然需要 JVM 的支持)
- 比如 exe4j :https://exe4j.apponic.com/download/
- 命令行
生成 Java 文档
- 开发完一个jar包,给别人提供一个使用文档
- 在代码中要使用文档注释,才会对应生成
- 生成步骤
- 点击顶部工具栏project->Generate JavaDoc
- 选择要生成的项目
- 选择public
- 选择生成文档的路径
- 点击next,继续点击next
- 输入文档的编码格式VM options下输入:
-encoding UTF-8 -charset UTF-8
- 点击finish
- 双击doc文件中的index就可以看内容
双括号初始化(Double Brace Initialization)
-
举例
List<Integer> list = new ArrayList<Integer>() *{ add(11); add(22); }}; //[11, 22] System.out.println(list);
- 特点:任何对象都可以用双括号初始化,在双括号内部使用该对象的成员方法
- 优缺点
- 优点: 代码简洁
- 缺点:本质是多生成了一个匿名类、可能会影响 equals 方法的正常使用
- 建议:慎重使用
网络编程
- 在 Java 中,使用
java.net.Socket、java.net.ServerSocket
可以实现 TCP 请求 - 在 Java 中,使用
java.net.DatagramSocket
可以实现 UDP 请求 - 代码示例
-
客户端代码:
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(); } }
-
服务器代码
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 实现网络爬虫
- 有个叫做 jsoup 的 Java 第三方库,可以用来编写基本的网络爬虫程序
-
下载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")); }