java高级的笔记

发布于:2024-05-01 ⋅ 阅读:(163) ⋅ 点赞:(0)

1 异常处理

1.1 异常概述

在Java中,异常(Exception)是一种处理错误情况的方式。当程序出现错误时,它会抛出一个异常对象,这个对象包含了关于错误的信息。Java通过异常处理机制允许程序员在运行时捕获并处理这些错误。

1.2 异常体系

Java异常体系基于两个主要的基类:ThrowableError

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 自定义异常的语法格式

自定义异常通常继承自ExceptionRuntimeException

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 集合的常用方法

  1. add(E e):向集合中添加一个元素。

  2. remove(Object o):从集合中删除指定的元素。

  3. contains(Object o):检查集合中是否包含指定的元素。

  4. size():返回集合中元素的数量。

  5. isEmpty():检查集合是否为空。

  6. clear():清空集合中的所有元素。

  7. 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 集合的常用方法

  1. add(E e):向集合中添加一个元素。

  2. add(int index, E element):在指定位置插入一个元素。

  3. remove(int index):删除指定位置的元素。

  4. remove(Object o):删除指定的元素。

  5. get(int index):获取指定位置的元素。

  6. set(int index, E element):设置指定位置的元素。

  7. size():返回集合中元素的数量。

  8. isEmpty():检查集合是否为空。

  9. clear():清空集合中的所有元素。

  10. 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 集合的常用方法

  1. put(K key, V value):向集合中添加一个键值对。

  2. remove(Object key):删除指定键的键值对。

  3. get(Object key):获取指定键的值。

  4. containsKey(Object key):检查集合中是否包含指定的键。

  5. containsValue(Object value):检查集合中是否包含指定的值。

  6. size():返回集合中键值对的数量。

  7. isEmpty():检查集合是否为空。

  8. clear():清空集合中的所有键值对。

  9. keySet():返回集合中所有键的集合。

  10. values():返回集合中所有值的集合。

  11. 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 类的构造器

  1. File(String pathname):构造一个表示指定路径名的 File 对象。

  2. File(String parent, String child):构造一个表示指定父路径名和子路径名的 File 对象。

  3. File(File parent, String child):构造一个表示指定父文件和子路径名的 File 对象。

3.1.3 File 类的常用方法

  1. createNewFile():创建一个新文件。

  2. delete():删除此文件或目录。

  3. exists():检查文件或目录是否存在。

  4. isFile():判断是否是文件。

  5. isDirectory():判断是否是目录。

  6. length():返回文件的大小(字节数)。

  7. listFiles():返回此目录中的所有文件和子目录。

  8. mkdir():创建一个新目录。

  9. mkdirs():创建一个新目录,包括任何必需的父目录。

  10. 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 流的分类

  1. 字节流:以字节为单位处理数据,主要用于处理二进制数据。

    • 输入流InputStream 类及其子类,如 FileInputStreamBufferedInputStream 等。

    • 输出流OutputStream 类及其子类,如 FileOutputStreamBufferedOutputStream 等。

  2. 字符流:以字符为单位处理数据,主要用于处理文本数据。

    • 输入流Reader 类及其子类,如 FileReaderBufferedReader 等。

    • 输出流Writer 类及其子类,如 FileWriterBufferedWriter 等。

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提供了两种主要的序列化方式:

  1. 实现Serializable接口:Java提供了Serializable接口作为标记接口,用于标识一个类可以被序列化。Serializable接口没有任何方法,只是一个标记接口,用于表示类的对象可以被序列化。

  2. 实现Externalizable接口:Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式。

3.3.4 序列化和反序列化的常用API

  1. java.io.ObjectOutputStream:代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

  2. 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 线程的生命周期包括以下几个阶段:

  1. 新建(New):当创建一个新的线程对象时,线程处于新建状态。

  2. 可运行(Runnable):当调用线程对象的 start() 方法时,线程进入可运行状态。此时,线程已经准备好运行,等待系统分配 CPU 资源。

  3. 运行(Running):当线程获得 CPU 资源后,线程开始执行 run() 方法中的代码,此时线程处于运行状态。

  4. 阻塞(Blocked):线程在运行过程中,可能会因为某些原因进入阻塞状态。例如,等待 I/O 操作完成、等待获取锁等。当阻塞条件解除后,线程会重新进入可运行状态。

  5. 等待(Waiting):线程在运行过程中,可能会进入等待状态。例如,调用 wait() 方法、join() 方法等。当其他线程执行相应操作后,线程会重新进入可运行状态。

  6. 超时等待(Timed Waiting):线程在运行过程中,可能会进入超时等待状态。例如,调用带有超时参数的 wait() 方法、join() 方法、sleep() 方法等。当超时时间到达后,线程会重新进入可运行状态。

  7. 终止(Terminated):当线程执行完 run() 方法中的代码或因为异常而终止时,线程进入终止状态。此时,线程的生命周期结束。

4.3 多线程实现方式

Java 提供了两种实现多线程的方式:

  1. 继承 Thread

class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的代码
    }
}
​
public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
  1. 实现 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,主要包括以下几个部分:

  1. InetAddress:表示互联网协议(IP)地址。

  2. Socket:用于实现客户端和服务器之间的通信。

  3. ServerSocket:用于监听来自客户端的连接请求。

  4. DatagramSocket:用于发送和接收数据报(UDP)。

5.2 Socket 编程

Socket 编程是 Java 网络编程的核心,它允许客户端和服务器之间建立连接并进行数据传输。以下是 Socket 编程的基本步骤:

  1. 创建一个 ServerSocket 对象,监听指定端口的连接请求。

  2. 创建一个 Socket 对象,连接到服务器。

  3. 通过 Socket 对象的输入流接收数据。

  4. 通过 Socket 对象的输出流发送数据。

  5. 关闭 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类的方法已经过时,因为它们的许多功能已由Calendarjava.time包中的类替代。不过,这里还是简要介绍DateDateFormat

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

网站公告

今日签到

点亮在社区的每一天
去签到