1 异常处理
1.1 异常概述
在Java中,异常(Exception)是一种处理错误情况的方式。当程序出现错误时,它会抛出一个异常对象,这个对象包含了关于错误的信息。Java通过异常处理机制允许程序员在运行时捕获并处理这些错误。
1.2 异常体系
Java异常体系基于两个主要的基类:Throwable
和 Error
。
Throwable
是所有错误和异常的父类。
-
Error
表示系统级别的错误,通常是虚拟机错误,这些错误通常不由程序处理。 -
Exception表示需要被程序捕获并处理的异常。
-
RuntimeException
是运行时异常,这些异常通常是因为编程错误导致的,如空指针异常(NullPointerException
)、数组越界异常(ArrayIndexOutOfBoundsException
)等。运行时异常不需要在方法签名中显式声明。 -
Checked Exception
(检查型异常)是除了RuntimeException
及其子类以外的异常。这些异常必须在方法签名中显式声明,或者使用try-catch
块进行捕获。
-
1.3 Java常见错误的异常
-
NullPointerException
:当应用程序试图在需要对象的地方使用null
时。 -
ArrayIndexOutOfBoundsException
:当应用程序试图访问数组的非法索引时。 -
ClassCastException
:当试图将对象强制转换为不是实例的子类时。 -
FileNotFoundException
:当试图打开不存在的文件时。 -
IOException
:当发生输入/输出错误时,这是很多I/O相关异常的父类。
1.4 异常处理
Java使用try-catch-finally
块来处理异常。
-
try
块:包含可能会抛出异常的代码。 -
catch
块:包含处理异常的代码。可以有多个catch
块来处理不同类型的异常。 -
finally
块:无论是否发生异常,都会执行的代码块。通常用于释放资源(如关闭文件或数据库连接)。
1.4.1 捕获异常(try-catch-finally)
try { // 可能会抛出异常的代码 File file = new File("nonexistentfile.txt"); FileReader fr = new FileReader(file); // ... } catch (FileNotFoundException e) { // 处理FileNotFoundException异常的代码 System.out.println("文件未找到:" + e.getMessage()); } catch (IOException e) { // 处理其他IO异常 System.out.println("I/O错误:" + e.getMessage()); } finally { // 无论是否发生异常,都会执行的代码 System.out.println("finally块被执行"); }
1.4.2 finally使用及举例
finally
块经常用于确保资源(如文件句柄、网络连接等)的释放,即使发生异常也会执行。
try (FileReader fr = new FileReader("somefile.txt")) { // 读取文件的代码 } catch (IOException e) { // 处理异常 } finally { // 无论是否发生异常,都会执行的代码 System.out.println("资源被释放"); }
注意:从Java 7开始,可以使用try-with-resources语句来自动关闭实现了AutoCloseable
接口的资源。
1.5 声明抛出异常类型(throws)
如果一个方法可能会抛出异常但不想在方法内部处理它,可以使用throws
关键字在方法签名中声明该方法可能会抛出的异常。
public void readFile(String filename) throws IOException { // ... 可能会抛出IOException的代码 }
1.6 自定义异常的语法格式
自定义异常通常继承自Exception
或RuntimeException
。
public class MyCustomException extends Exception { public MyCustomException(String message) { super(message); } // 可以添加其他方法或构造器 } // 使用自定义异常 public void doSomething() throws MyCustomException { // ... if (/* 某种条件 */) { throw new MyCustomException("发生了自定义异常"); } // ... }
2 集合
2.1 Set集合
2.1.1 Set 集合概述
Set 集合是一个不包含重复元素的集合,它继承了 Collection 接口。Set 集合中的元素不按照特定的顺序排列,因此它不保证元素的顺序。
2.1.2 Set特点
-
存储键值对(key-value pairs)的集合。
-
每个键都是唯一的,但值可以重复。
-
Map集合与Collection集合没有继承关系,它们是并行的两个集合体系。
2.1.3 Set 集合的常用方法
-
add(E e)
:向集合中添加一个元素。 -
remove(Object o)
:从集合中删除指定的元素。 -
contains(Object o)
:检查集合中是否包含指定的元素。 -
size()
:返回集合中元素的数量。 -
isEmpty()
:检查集合是否为空。 -
clear()
:清空集合中的所有元素。 -
iterator()
:返回一个用于遍历集合中元素的迭代器。
2.1.4 Set 集合的主要实现类
例1:HashSet:基于哈希表实现的 Set 集合,它提供了快速的插入、删除和查找操作。HashSet 不保证元素的顺序。
import java.util.HashSet; public class HashSetExample { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("apple"); set.add("banana"); set.add("orange"); set.add("apple"); // 重复元素,不会被添加 System.out.println(set); // 输出:[orange, banana, apple] } }
例2:LinkedHashSet:基于哈希表和链表实现的 Set 集合,它继承了 HashSet,但保持了元素的插入顺序。
import java.util.LinkedHashSet; public class LinkedHashSetExample { public static void main(String[] args) { LinkedHashSet<String> set = new LinkedHashSet<>(); set.add("apple"); set.add("banana"); set.add("orange"); set.add("apple"); // 重复元素,不会被添加 System.out.println(set); // 输出:[apple, banana, orange] } }
例3:TreeSet:基于红黑树实现的有序 Set 集合,它可以对元素进行排序。默认情况下,元素按照自然顺序排序,也可以通过传入自定义的 Comparator 进行排序。
import java.util.TreeSet; public class TreeSetExample { public static void main(String[] args) { TreeSet<String> set = new TreeSet<>(); set.add("apple"); set.add("banana"); set.add("orange"); set.add("apple"); // 重复元素,不会被添加 System.out.println(set); // 输出:[apple, banana, orange] } }
2.2 List 集合
2.2.1 List 集合概述
List 集合是一个有序集合,它继承了 Collection 接口。List 集合中的元素可以重复,且元素按照特定的顺序排列。
2.2.2 特点:
-
有序集合,可以存储重复的元素。
-
用户可以精准地控制元素插入的位置。
-
可以通过索引访问元素。
2.2.3 List 集合的常用方法
-
add(E e)
:向集合中添加一个元素。 -
add(int index, E element)
:在指定位置插入一个元素。 -
remove(int index)
:删除指定位置的元素。 -
remove(Object o)
:删除指定的元素。 -
get(int index)
:获取指定位置的元素。 -
set(int index, E element)
:设置指定位置的元素。 -
size()
:返回集合中元素的数量。 -
isEmpty()
:检查集合是否为空。 -
clear()
:清空集合中的所有元素。 -
iterator()
:返回一个用于遍历集合中元素的迭代器。
2.2.4 List 集合的主要实现类
例1:ArrayList:基于动态数组实现的 List 集合,它提供了快速的随机访问。
import java.util.ArrayList; public class ArrayListExample { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("apple"); list.add("banana"); list.add("orange"); System.out.println(list); // 输出:[apple, banana, orange] } }
例2:LinkedList:基于双向链表实现的 List 集合,它提供了快速的插入和删除操作。
import java.util.LinkedList; public class LinkedListExample { public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); list.add("apple"); list.add("banana"); list.add("orange"); System.out.println(list); // 输出:[apple, banana, orange] } }
2.3 Map 集合
2.3.1 Map 集合概述
Map 集合是一种键值对的数据结构,它继承了 Collection 接口。Map 集合中的键是唯一的,但值可以重复。Map 集合中的元素以键值对的形式存储,可以通过键来快速查找对应的值。
2.3.2 特点:
-
存储键值对(key-value pairs)的集合。
-
每个键都是唯一的,但值可以重复。
-
Map集合与Collection集合没有继承关系,它们是并行的两个集合体系。
2.3.3 Map 集合的常用方法
-
put(K key, V value)
:向集合中添加一个键值对。 -
remove(Object key)
:删除指定键的键值对。 -
get(Object key)
:获取指定键的值。 -
containsKey(Object key)
:检查集合中是否包含指定的键。 -
containsValue(Object value)
:检查集合中是否包含指定的值。 -
size()
:返回集合中键值对的数量。 -
isEmpty()
:检查集合是否为空。 -
clear()
:清空集合中的所有键值对。 -
keySet()
:返回集合中所有键的集合。 -
values()
:返回集合中所有值的集合。 -
entrySet()
:返回集合中所有键值对的集合。
2.3.4 Map 集合的主要实现类
例1:HashMap:基于哈希表实现的 Map 集合,它提供了快速的插入、删除和查找操作。HashMap 不保证元素的顺序。
import java.util.HashMap; public class HashMapExample { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); System.out.println(map); // 输出:{orange=3, banana=2, apple=1} } }
例2:LinkedHashMap:基于哈希表和链表实现的 Map 集合,它继承了 HashMap,但保持了元素的插入顺序。
import java.util.LinkedHashMap; public class LinkedHashMapExample { public static void main(String[] args) { LinkedHashMap<String, Integer> map = new LinkedHashMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); System.out.println(map); // 输出:{apple=1, banana=2, orange=3} } }
例3:TreeMap:基于红黑树实现的有序 Map 集合,它可以对键进行排序。默认情况下,键按照自然顺序排序,也可以通过传入自定义的 Comparator 进行排序。
import java.util.TreeMap; public class TreeMapExample { public static void main(String[] args) { TreeMap<String, Integer> map = new TreeMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); System.out.println(map); // 输出:{apple=1, banana=2, orange=3} } }
3 File类与IO流
3.1 File类
在 Java 中,File
类是用于表示文件或目录的路径名的类
3.1.1 File 类概述
File
类提供了许多方法来操作文件或目录,如创建、删除、重命名、获取文件属性(如大小、修改时间等)以及判断文件类型(如是否是文件、是否是目录等)。
3.1.2 File 类的构造器
-
File(String pathname)
:构造一个表示指定路径名的File
对象。 -
File(String parent, String child)
:构造一个表示指定父路径名和子路径名的File
对象。 -
File(File parent, String child)
:构造一个表示指定父文件和子路径名的File
对象。
3.1.3 File 类的常用方法
-
createNewFile()
:创建一个新文件。 -
delete()
:删除此文件或目录。 -
exists()
:检查文件或目录是否存在。 -
isFile()
:判断是否是文件。 -
isDirectory()
:判断是否是目录。 -
length()
:返回文件的大小(字节数)。 -
listFiles()
:返回此目录中的所有文件和子目录。 -
mkdir()
:创建一个新目录。 -
mkdirs()
:创建一个新目录,包括任何必需的父目录。 -
renameTo(File dest)
:重命名此文件或目录。
3.1.4 File 类的案例
例1:创建一个新文件:
import java.io.File; import java.io.IOException; public class FileExample { public static void main(String[] args) { File file = new File("example.txt"); try { if (file.createNewFile()) { System.out.println("文件创建成功"); } else { System.out.println("文件已存在"); } } catch (IOException e) { e.printStackTrace(); } } }
例2:删除一个文件:
import java.io.File; public class FileExample { public static void main(String[] args) { File file = new File("example.txt"); if (file.delete()) { System.out.println("文件删除成功"); } else { System.out.println("文件删除失败"); } } }
例3:检查文件或目录是否存在:
import java.io.File; public class FileExample { public static void main(String[] args) { File file = new File("example.txt"); if (file.exists()) { System.out.println("文件或目录存在"); } else { System.out.println("文件或目录不存在"); } } }
例4:创建一个新目录:
import java.io.File; public class FileExample { public static void main(String[] args) { File dir = new File("example_dir"); if (dir.mkdir()) { System.out.println("目录创建成功"); } else { System.out.println("目录创建失败"); } } }
3.2 IO 流
3.2.1 IO 流原理
Java IO 流(Input/Output Stream)是 Java 中用于读取和写入数据的通道。IO 流可以从文件、网络连接或其他数据源读取数据,也可以将数据写入文件、网络连接或其他数据目标。
3.2.2 流的分类
-
字节流:以字节为单位处理数据,主要用于处理二进制数据。
-
输入流:
InputStream
类及其子类,如FileInputStream
、BufferedInputStream
等。 -
输出流:
OutputStream
类及其子类,如FileOutputStream
、BufferedOutputStream
等。
-
-
字符流:以字符为单位处理数据,主要用于处理文本数据。
-
输入流:
Reader
类及其子类,如FileReader
、BufferedReader
等。 -
输出流:
Writer
类及其子类,如FileWriter
、BufferedWriter
等。
-
3.2.3 常用方法
例1:FileInputStream:从文件中读取字节数据。
import java.io.FileInputStream; import java.io.IOException; public class FileInputStreamExample { public static void main(String[] args) { try (FileInputStream fis = new FileInputStream("example.txt")) { int data; while ((data = fis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } } }
例2:FileOutputStream:将字节数据写入文件。
import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamExample { public static void main(String[] args) { try (FileOutputStream fos = new FileOutputStream("output.txt")) { String content = "Hello, World!"; fos.write(content.getBytes()); } catch (IOException e) { e.printStackTrace(); } } }
例3:BufferedReader:从文件中读取字符数据,支持按行读取。
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BufferedReaderExample { public static void main(String[] args) { try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) { String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
例4:BufferedWriter:将字符数据写入文件,支持按行写入。
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class BufferedWriterExample { public static void main(String[] args) { try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) { String content = "Hello, World!\n"; bw.write(content); } catch (IOException e) { e.printStackTrace(); } } }
例5:DataInputStream:从文件中读取基本数据类型。
import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; public class DataInputStreamExample { public static void main(String[] args) { try (DataInputStream dis = new DataInputStream(new FileInputStream("example.bin"))) { int num = dis.readInt(); System.out.println("读取到的整数: " + num); } catch (IOException e) { e.printStackTrace(); } } }
例6:DataOutputStream:将基本数据类型写入文件。
import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class DataOutputStreamExample { public static void main(String[] args) { try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("output.bin"))) { int num = 42; dos.writeInt(num); } catch (IOException e) { e.printStackTrace(); } } }
3.3 序列化与反序列化
3.3.1 序列化与反序列化的概念
Java序列化是指将一个Java对象转换成字节序列,以便在网络上传输或存储在本地磁盘中。而反序列化则是将已经序列化的字节序列恢复为Java对象。
3.3.2 序列化的重要性
序列化机制使得对象可以脱离程序的运行而独立存在。所有在网络上传输的对象都必须是可序列化的,如RMI(远程方法调用),传入的参数或返回的对象都必须是可序列化的,否则会出错。同样,所有必须保存到磁盘的Java对象也必须是可序列化的。
3.3.3 实现序列化的方式
Java提供了两种主要的序列化方式:
-
实现Serializable接口:Java提供了Serializable接口作为标记接口,用于标识一个类可以被序列化。Serializable接口没有任何方法,只是一个标记接口,用于表示类的对象可以被序列化。
-
实现Externalizable接口:Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式。
3.3.4 序列化和反序列化的常用API
-
java.io.ObjectOutputStream:代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
-
java.io.ObjectInputStream:代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
3.3.5 序列化案例
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; class Person implements Serializable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } public class SerializationExample { public static void main(String[] args) { Person person = new Person("John Doe", 30); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) { oos.writeObject(person); System.out.println("对象序列化成功"); } catch (IOException e) { e.printStackTrace(); } } }
3.3.6 反序列化
反序列化(Deserialization)是将字节流转换回对象的过程。反序列化的过程可以通过 java.io.ObjectInputStream
类实现。
3.3.7 反序列化案例
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; class Person implements Serializable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } public class DeserializationExample { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) { Person person = (Person) ois.readObject(); System.out.println("对象反序列化成功"); System.out.println("姓名: " + person.getName()); System.out.println("年龄: " + person.getAge()); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
4 多线程
4.1 多线程概念
多线程(Multithreading)是指在一个程序中同时运行多个线程,以实现并发执行。多线程可以提高程序的执行效率,充分利用 CPU 资源。
4.2 多线程生命周期
Java 线程的生命周期包括以下几个阶段:
-
新建(New):当创建一个新的线程对象时,线程处于新建状态。
-
可运行(Runnable):当调用线程对象的
start()
方法时,线程进入可运行状态。此时,线程已经准备好运行,等待系统分配 CPU 资源。 -
运行(Running):当线程获得 CPU 资源后,线程开始执行
run()
方法中的代码,此时线程处于运行状态。 -
阻塞(Blocked):线程在运行过程中,可能会因为某些原因进入阻塞状态。例如,等待 I/O 操作完成、等待获取锁等。当阻塞条件解除后,线程会重新进入可运行状态。
-
等待(Waiting):线程在运行过程中,可能会进入等待状态。例如,调用
wait()
方法、join()
方法等。当其他线程执行相应操作后,线程会重新进入可运行状态。 -
超时等待(Timed Waiting):线程在运行过程中,可能会进入超时等待状态。例如,调用带有超时参数的
wait()
方法、join()
方法、sleep()
方法等。当超时时间到达后,线程会重新进入可运行状态。 -
终止(Terminated):当线程执行完
run()
方法中的代码或因为异常而终止时,线程进入终止状态。此时,线程的生命周期结束。
4.3 多线程实现方式
Java 提供了两种实现多线程的方式:
-
继承
Thread
类:
class MyThread extends Thread { @Override public void run() { // 线程执行的代码 } } public class Main { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } }
-
实现
Runnable
接口:
class MyRunnable implements Runnable { @Override public void run() { // 线程执行的代码 } } public class Main { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); } }
4.4 多线程案例
案例 1:创建两个线程,分别输出奇数和偶数
class PrintNumbers implements Runnable { private int start; private int end; public PrintNumbers(int start, int end) { this.start = start; this.end = end; } @Override public void run() { for (int i = start; i <= end; i++) { System.out.println(Thread.currentThread().getName() + ": " + i); } } } public class MultiThreadExample { public static void main(String[] args) { Thread t1 = new Thread(new PrintNumbers(1, 50), "奇数线程"); Thread t2 = new Thread(new PrintNumbers(2, 50), "偶数线程"); t1.start(); t2.start(); } }
案例2:使用 synchronized
关键字实现线程同步
class SharedResource { private int counter = 0; public synchronized void increment() { counter++; } public synchronized int getCounter() { return counter; } } class IncrementThread extends Thread { private SharedResource sharedResource; public IncrementThread(SharedResource sharedResource) { this.sharedResource = sharedResource; } @Override public void run() { for (int i = 0; i < 100; i++) { sharedResource.increment(); } } } public class SynchronizedExample { public static void main(String[] args) throws InterruptedException { SharedResource sharedResource = new SharedResource(); Thread t1 = new IncrementThread(sharedResource); Thread t2 = new IncrementThread(sharedResource); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("Counter: " + sharedResource.getCounter()); } }
5 网络编程
在 Java 中,网络编程是指编写程序实现数据在计算机之间的传输
5.1 网络编程概述
Java 提供了一套丰富的网络编程 API,主要包括以下几个部分:
-
InetAddress:表示互联网协议(IP)地址。
-
Socket:用于实现客户端和服务器之间的通信。
-
ServerSocket:用于监听来自客户端的连接请求。
-
DatagramSocket:用于发送和接收数据报(UDP)。
5.2 Socket 编程
Socket 编程是 Java 网络编程的核心,它允许客户端和服务器之间建立连接并进行数据传输。以下是 Socket 编程的基本步骤:
-
创建一个 ServerSocket 对象,监听指定端口的连接请求。
-
创建一个 Socket 对象,连接到服务器。
-
通过 Socket 对象的输入流接收数据。
-
通过 Socket 对象的输出流发送数据。
-
关闭 Socket 对象。
5.3 Socket 相关 API
1. java.net.Socket:表示一个套接字,用于实现客户端和服务器之间的通信。
Socket socket = new Socket("localhost", 8080);
2. java.net.ServerSocket:用于监听来自客户端的连接请求。
ServerSocket serverSocket = new ServerSocket(8080); Socket socket = serverSocket.accept();
3. java.net.InetAddress:表示互联网协议(IP)地址。
InetAddress address = InetAddress.getByName("www.example.com");
4. java.net.DatagramSocket:用于发送和接收数据报(UDP)。
DatagramSocket datagramSocket = new DatagramSocket(8080);
5.4 Socket 案例
示例 1:创建一个简单的 Socket 服务器和客户端
服务器端代码:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8080); Socket socket = serverSocket.accept(); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); String line; while ((line = reader.readLine()) != null) { System.out.println("Received: " + line); writer.println("Server received: " + line); } socket.close(); serverSocket.close(); } }
客户端代码:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception { Socket socket = new Socket("localhost", 8080); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); writer.println("Hello, Server!"); String line; while ((line = reader.readLine()) != null) { System.out.println("Received: " + line); } socket.close(); } }
示例 2:创建一个简单的多线程 Socket 服务器
服务器端代码:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class MultiThreadServer { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8080); while (true) { Socket socket = serverSocket.accept(); new Thread(new ClientHandler(socket)).start(); } } } class ClientHandler implements Runnable { private Socket socket; public ClientHandler(Socket socket) { this.socket = socket; } @Override public void run() { try { BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); String line; while ((line = reader.readLine()) != null) { System.out.println("Received: " + line); writer.println("Server received: " + line); } socket.close(); } catch (Exception e) { e.printStackTrace(); } } }
客户端代码:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception { Socket socket = new Socket("localhost", 8080); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); writer.println("Hello, Server!"); String line; while ((line = reader.readLine()) != null) { System.out.println("Received: " + line); } socket.close(); } }
6 常用的API
6.1 String类
String
是Java中的不可变字符序列。一旦创建,就不能改变其值。
6.1.1 常用方法:
-
length()
: 返回字符串的长度。 -
charAt(int index)
: 返回指定索引处的字符。 -
substring(int beginIndex, int endIndex)
: 返回一个新字符串,它是此字符串的一个子字符串。 -
indexOf(int ch, int fromIndex)
: 返回指定字符在此字符串中第一次出现处的索引,从指定的索引开始搜索。 -
lastIndexOf(int ch, int fromIndex)
: 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 -
replace(char oldChar, char newChar)
: 返回一个新的字符串,它是通过用newChar
替换此字符串中出现的所有oldChar
得到的。 -
equals(Object anObject)
: 比较此字符串与指定的对象是否相等。 -
equalsIgnoreCase(String anotherString)
: 将此String
与另一个String
进行比较,不考虑大小写。
6.1.2 案例:
public class StringDemo { public static void main(String[] args) { String str = "Hello, World!"; System.out.println("Length: " + str.length()); System.out.println("Character at index 0: " + str.charAt(0)); System.out.println("Substring from 0 to 5: " + str.substring(0, 5)); System.out.println("Index of 'o': " + str.indexOf('o')); System.out.println("New string with 'l' replaced by 'L': " + str.replace('l', 'L')); System.out.println("Equals: " + str.equals("Hello, World!")); System.out.println("EqualsIgnoreCase: " + str.equalsIgnoreCase("hello, world!")); } }
6.2 StringBuffer类
StringBuffer
是一个可变的字符序列。与String
相比,StringBuffer
允许对字符序列进行修改。
6.2.1 常用方法:
-
append(String str)
: 将指定的字符串追加到此字符序列的末尾。 -
insert(int offset, String str)
: 在此字符序列的指定位置插入给定的字符串。 -
delete(int start, int end)
: 移除此序列的子字符串中的字符。 -
replace(int start, int end, String str)
: 用给定字符串替换此序列的子字符串中的字符。
6.2.2 案例:
public class StringBufferDemo { public static void main(String[] args) { StringBuffer sb = new StringBuffer("Hello"); sb.append(", World!"); System.out.println(sb.toString()); // 输出: Hello, World! sb.insert(7, " Java"); System.out.println(sb.toString()); // 输出: Hello, Java World! sb.delete(7, 11); System.out.println(sb.toString()); // 输出: Hello, World! sb.replace(7, 12, "Universe"); System.out.println(sb.toString()); // 输出: Hello, Universe! } }
6.3 Date和DateFormat类
Date
类表示特定的瞬间,精确到毫秒。但是,Date
类的方法已经过时,因为它们的许多功能已由Calendar
和java.time
包中的类替代。不过,这里还是简要介绍Date
和DateFormat
。
6.3.1 常用方法(对于Date
类):
-
getTime()
: 返回自1970年1月1日 00:00:00 GMT以来的此Date
对象的毫秒偏移量。
DateFormat:
-
DateFormat
是一个用于日期/时间格式化和解析的抽象类。通常使用其子类SimpleDateFormat
。
6.3.2案例:
import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; public class DateDemo { public static void main(String[] args) { Date date = new Date(); System.out.println("Current Date: " + date.toString()); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String formattedDate = dateFormat