目录
👉🏻实现客户端和服务端交互
Java 的网络编程是通过 Java 提供的标准库来实现的,主要依赖于 java.net
包。以下是一些基础概念和常用类的介绍:
1. 基本概念
- 客户端-服务器模型:在网络编程中,通常采用客户端-服务器架构,其中客户端向服务器发送请求,服务器处理请求并返回响应。
- Socket:Socket 是实现网络通信的基本单元,能够在不同主机上进行数据交换。
2. 常用类
- Socket:用于客户端与服务器之间的连接。
- ServerSocket:用于服务器端监听客户端请求。
- InetAddress:用于表示 IP 地址。
- URL:用于处理统一资源定位符,提供访问网络资源的功能。
- URLConnection:用于与 URL 进行交互。
3. 简单示例
客户端代码
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 12345)) {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println("Hello, Server!");
String response = in.readLine();
System.out.println("Server response: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器代码
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("Server is listening on port 8888");
while (true) {
Socket socket = serverSocket.accept();
new Thread(new ClientHandler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ClientHandler implements Runnable {
private Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = in.readLine();
System.out.println("Received: " + message);
out.println("Echo: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 注意事项
- 多线程:服务器通常需要处理多个客户端连接,因此使用多线程是一个常见的做法。
- 异常处理:网络编程中,异常处理非常重要,以确保程序的稳定性。
- 资源管理:确保在使用完 Socket 和 I/O 流后关闭它们,以避免资源泄漏。
👉🏻实现客户端聊天窗口
SimpleChatServer
package MyPackage2;
import java.io.*;
import java.net.*;
import java.util.*;
public class SimpleChatServer {
ArrayList<PrintWriter> clientOutputStreams;
public static void main(String[] args) {
new SimpleChatServer().go();
}
public void go() {
//请手动输入代码
clientOutputStreams = new ArrayList<>();
try {
ServerSocket serverSocket = new ServerSocket(5000);
while(true)
{
Socket clientSocket = serverSocket.accept();
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
clientOutputStreams.add(writer);
//创建一个线程,用于接收客户消息
Thread t = new Thread(new ClientHandler(clientSocket));
t.start();
System.out.println("got a connection");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket socket;
public ClientHandler(Socket clientSocket) {
//请手动输入代码
try {
socket = clientSocket;
InputStreamReader isReader = new InputStreamReader(clientSocket.getInputStream());
reader = new BufferedReader(isReader);
}catch (Exception ex){
ex.printStackTrace();
}
}
public void run() {
String message;
try {
while ((message = reader.readLine()) != null) {
String printMessage = socket.getPort() + "端口:"+message;
System.out.println("read: " + printMessage);
tellEveryone(printMessage);
}
} catch (Exception ex) {
//ex.printStackTrace();
}
}
}
public void tellEveryone(String message) {
//请手动输入代码
Iterator<PrintWriter> it = clientOutputStreams.iterator();
while(it.hasNext()){
try {
PrintWriter writer = it.next();
writer.println(message);
writer.flush();//刷新缓冲区
}catch (Exception ex){
ex.printStackTrace();
}
}
}
}
SimpleChatClient
package MyPackage2;
import java.io.*;
import java.net.*;
import java.util.*;
public class SimpleChatServer {
ArrayList<PrintWriter> clientOutputStreams;
public static void main(String[] args) {
new SimpleChatServer().go();
}
public void go() {
//请手动输入代码
clientOutputStreams = new ArrayList<>();
try {
ServerSocket serverSocket = new ServerSocket(5000);
while(true)
{
Socket clientSocket = serverSocket.accept();
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
clientOutputStreams.add(writer);
//创建一个线程,用于接收客户消息
Thread t = new Thread(new ClientHandler(clientSocket));
t.start();
System.out.println("got a connection");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket socket;
public ClientHandler(Socket clientSocket) {
//请手动输入代码
try {
socket = clientSocket;
InputStreamReader isReader = new InputStreamReader(clientSocket.getInputStream());
reader = new BufferedReader(isReader);
}catch (Exception ex){
ex.printStackTrace();
}
}
public void run() {
String message;
try {
while ((message = reader.readLine()) != null) {
String printMessage = socket.getPort() + "端口:"+message;
System.out.println("read: " + printMessage);
tellEveryone(printMessage);
}
} catch (Exception ex) {
//ex.printStackTrace();
}
}
}
public void tellEveryone(String message) {
//请手动输入代码
Iterator<PrintWriter> it = clientOutputStreams.iterator();
while(it.hasNext()){
try {
PrintWriter writer = it.next();
writer.println(message);
writer.flush();//刷新缓冲区
}catch (Exception ex){
ex.printStackTrace();
}
}
}
}
👉🏻 Java Swing
JTextArea
JTextArea
是 Java Swing 中用于显示和编辑多行文本的组件。它是一个非常灵活的文本区域,可以用于各种图形用户界面(GUI)应用程序。以下是 JTextArea
的一些主要特点和用法:
主要特点
-
多行文本:可以显示和编辑多行文本,适合用于输入较长的内容,如文章、评论等。
-
可滚动:通常与
JScrollPane
一起使用,以便在文本较多时提供滚动功能。 -
文本格式化:支持基本的文本格式化,比如设置字体、大小、颜色等。
-
换行和自动换行:
- 可以设置为自动换行,确保长文本在可见区域内换行。
- 也可以禁用换行,使文本在一行中显示。
-
事件处理:可以添加监听器来处理用户的输入事件,比如键盘输入、焦点变化等。
常用方法
-
构造函数:
JTextArea textArea = new JTextArea(rows, columns);
可以指定文本区域的行数和列数。
-
设置文本:
textArea.setText("初始文本");
-
获取文本:
String text = textArea.getText();
-
追加文本:
textArea.append("要追加的文本");
-
清空文本:
textArea.setText("");
-
设置可编辑性:
textArea.setEditable(false); // 设为不可编辑
-
设置换行:
textArea.setLineWrap(true); // 启用自动换行 textArea.setWrapStyleWord(true); // 仅在单词边界处换行
示例代码
下面是一个简单的示例,展示如何创建一个包含 JTextArea
的 GUI 应用:
import javax.swing.*;
import java.awt.*;
public class TextAreaExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JTextArea 示例");
JTextArea textArea = new JTextArea(10, 30);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
JTextField
JTextField
是 Java Swing 中用于单行文本输入的组件。它非常适合用于收集短文本数据,如用户名、密码、搜索框等。以下是 JTextField
的一些主要特点和用法:
主要特点
-
单行输入:
JTextField
设计用于输入单行文本,适合处理简单的数据输入。 -
可编辑性:用户可以点击文本框并输入或编辑文本。
-
占位符文本:可以设置提示文本,引导用户输入所需格式的信息。
-
事件处理:支持键盘事件,可以添加监听器来处理文本更改事件、焦点事件等。
-
限制输入:可以通过设置文档过滤器或自定义逻辑来限制用户输入的字符类型。
常用方法
-
构造函数:
JTextField textField = new JTextField(columns);
可以指定文本框的列数,影响其宽度。
-
设置文本:
textField.setText("初始文本");
-
获取文本:
String text = textField.getText();
-
清空文本:
textField.setText("");
-
设置可编辑性:
textField.setEditable(false); // 设置为不可编辑
-
添加事件监听:
textField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 处理事件 } });
示例代码
下面是一个简单的示例,展示如何创建一个包含 JTextField
的 GUI 应用:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TextFieldExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JTextField 示例");
JTextField textField = new JTextField(20); // 创建一个宽度为20列的文本框
JButton button = new JButton("提交");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String inputText = textField.getText(); // 获取输入文本
JOptionPane.showMessageDialog(frame, "您输入的文本是: " + inputText);
}
});
JPanel panel = new JPanel();
panel.add(textField);
panel.add(button);
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
JFrame
JFrame
是 Java Swing 中用于创建窗口的主要组件。它代表一个应用程序的主窗口,用户可以在其中添加各种其他组件(如按钮、文本框等)。以下是 JFrame
的一些主要特点和用法:
主要特点
-
窗口管理:
JFrame
提供了一个可见的界面,用户可以通过它与应用程序交互。 -
标题栏:可以为窗口设置标题,这将显示在窗口的标题栏中。
-
关闭操作:可以设置窗口关闭时的行为,比如退出应用程序或隐藏窗口。
-
布局管理:支持多种布局管理器,可以控制组件在窗口中的排列方式。
-
菜单栏:可以为窗口添加菜单栏,以提供更多功能选项。
常用方法
-
构造函数:
JFrame frame = new JFrame("窗口标题");
-
设置默认关闭操作:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 退出程序
-
设置大小:
frame.setSize(400, 300); // 设置宽度和高度
-
设置可见性:
frame.setVisible(true); // 显示窗口
-
添加组件:
frame.add(component); // 向窗口添加组件
-
设置布局:
frame.setLayout(new FlowLayout()); // 设置流式布局
示例代码
下面是一个简单的示例,展示如何创建一个基本的 JFrame
窗口并在其中添加一些组件:
import javax.swing.*;
import java.awt.*;
public class JFrameExample {
public static void main(String[] args) {
// 创建窗口
JFrame frame = new JFrame("JFrame 示例");
// 设置默认关闭操作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置窗口大小
frame.setSize(400, 300);
// 设置布局
frame.setLayout(new FlowLayout());
// 添加组件
JLabel label = new JLabel("欢迎使用 JFrame!");
JButton button = new JButton("点击我");
frame.add(label);
frame.add(button);
// 设置窗口可见
frame.setVisible(true);
}
}
JPanel
JPanel
是 Java Swing 中一个重要的容器组件,用于组织和管理其他组件。它可以用来分组相关的组件,并提供灵活的布局管理选项。以下是 JPanel
的一些主要特点和用法:
主要特点
-
容器:
JPanel
可以包含多个组件(如按钮、文本框等),并能有效地管理它们的布局。 -
布局管理:可以使用不同的布局管理器(如
FlowLayout
、BorderLayout
、GridLayout
等)来控制组件的排列方式。 -
可绘制性:你可以重写
paintComponent
方法,在JPanel
上自定义绘制图形或背景。 -
轻量级组件:
JPanel
是一个轻量级组件,不会直接影响 GUI 的性能,适合用于构建复杂界面。 -
支持透明背景:通过设置透明度,可以实现更复杂的视觉效果。
常用方法
-
构造函数:
JPanel panel = new JPanel();
-
设置布局:
panel.setLayout(new FlowLayout()); // 设置为流式布局
-
添加组件:
panel.add(component); // 向面板添加组件
-
设置背景颜色:
panel.setBackground(Color.LIGHT_GRAY); // 设置背景颜色
-
绘制自定义内容:
@Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 自定义绘制代码 }
示例代码
下面是一个简单的示例,展示如何创建一个 JPanel
并在其中添加一些组件:
import javax.swing.*;
import java.awt.*;
public class JPanelExample {
public static void main(String[] args) {
// 创建主窗口
JFrame frame = new JFrame("JPanel 示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
// 创建面板
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.setBackground(Color.LIGHT_GRAY); // 设置背景颜色
// 添加组件
JLabel label = new JLabel("欢迎使用 JPanel!");
JButton button = new JButton("点击我");
panel.add(label);
panel.add(button);
// 将面板添加到窗口
frame.add(panel);
// 显示窗口
frame.setVisible(true);
}
}
JScrollPane
JScrollPane
是 Java Swing 中用于提供滚动功能的组件,它允许用户在一个固定大小的区域中查看比该区域大得多的内容。通常,JScrollPane
主要用于包含长文本或大型图像等内容,以便用户能够通过滚动条进行查看。
主要特点
-
自动生成滚动条:当内容超出可视区域时,
JScrollPane
会自动添加水平和/或垂直滚动条。 -
灵活的内容容器:可以将任何组件(如
JPanel
、JTextArea
等)放入JScrollPane
中,从而使其支持滚动。 -
控制滚动条的行为:可以设置滚动条的政策(例如总是显示、只在需要时显示等)。
-
支持平滑滚动:可以通过程序控制滚动位置,实现更好的用户体验。
常用方法
-
构造函数:
JScrollPane scrollPane = new JScrollPane();
-
设置内容:
scrollPane.setViewportView(component); // 设置可滚动的组件
-
设置滚动条策略:
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); // 始终显示垂直滚动条
-
获取滚动条:
JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar(); // 获取垂直滚动条
示例代码
下面是一个简单的例子,展示如何使用 JScrollPane
来创建一个带有滚动条的文本区域:
import javax.swing.*;
public class JScrollPaneExample {
public static void main(String[] args) {
// 创建主窗口
JFrame frame = new JFrame("JScrollPane 示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
// 创建文本区域
JTextArea textArea = new JTextArea(20, 30); // 20 行,30 列
for (int i = 1; i <= 100; i++) {
textArea.append("行 " + i + "\n"); // 添加内容
}
// 创建滚动面板并添加文本区域
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); // 始终显示垂直滚动条
// 将滚动面板添加到窗口
frame.add(scrollPane);
// 显示窗口
frame.setVisible(true);
}
}
👉🏻多线程
Java 的多线程是指在一个程序中同时执行多个线程,以提高程序的效率和响应能力。多线程可以让 CPU 更有效地利用,特别是在处理 I/O 操作或计算密集型任务时。
1. 线程的基本概念
- 线程:线程是程序执行的最小单位,一个 Java 应用程序至少有一个主线程。
- 进程:进程是系统中运行的程序的实例,它可以包含一个或多个线程。
2. 创建线程的方法
Java 提供了两种创建线程的方式:
2.1 继承 Thread
类
class MyThread extends Thread {
public void run() {
System.out.println("线程正在运行");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
2.2 实现 Runnable
接口
class MyRunnable implements Runnable {
public void run() {
System.out.println("线程正在运行");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // 启动线程
}
}
3. 线程的生命周期
线程的生命周期包括以下几个状态:
- 新建(New):线程被创建,但还未启动。
- 就绪(Runnable):线程已启动,并在等待 CPU 调度。
- 运行(Running):线程正在执行。
- 阻塞(Blocked):线程在等待锁资源。
- 等待(Waiting):线程在等待其他线程的通知或完成。
- 终止(Terminated):线程运行结束。
4. 线程同步
由于多个线程可能会访问共享资源,导致数据不一致,因此需要使用线程同步来控制对共享资源的访问。
4.1 使用 synchronized
关键字
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
4.2 使用 Lock
接口
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
5. 线程通信
Java 提供了线程间通信机制,可以使用 wait()
、notify()
和 notifyAll()
方法。
class SharedResource {
private int value;
public synchronized void produce(int newValue) {
value = newValue;
notify(); // 通知消费者线程
}
public synchronized int consume() throws InterruptedException {
while (value == 0) {
wait(); // 等待生产者线程
}
return value;
}
}
6. 线程池
为了提高性能并管理线程的生命周期,Java 提供了线程池。通过 Executors
类可以方便地创建和管理线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executor.submit(() -> {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行");
});
}
executor.shutdown(); // 关闭线程池
}
}
如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长