1.实现单例模式 (Singleton Pattern) 懒汉式: 使用双重检查锁定 (DCL) 实现线程安全的懒汉式单例模式。这种模式在第一次调用时才创建实例,并且通过两次检查和同步块确保了线程安全和性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Singleton { private static volatile Singleton instance; private Singleton () {} public static Singleton getInstance () { if (instance == null ) { synchronized (Singleton.class) { if (instance == null ) { instance = new Singleton (); } } } return instance; } public void showMessage () { System.out.println("这是一个线程安全的懒汉式单例模式实例。" ); } }
饿汉式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package test1;class SingletonEager { private static final SingletonEager INSTANCE = new SingletonEager (); private SingletonEager () {} public static SingletonEager getInstance () { return INSTANCE; } public void showMessage () { System.out.println("这是一个线程安全的饿汉式单例模式实例。" ); } }
2.继承与多态 (Inheritance and Polymorphism) 设计一个 Animal
抽象类,并创建 Dog
和 Cat
类来展示继承和多态。=
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 abstract class Animal { public abstract void eat () ; } class Dog extends Animal { @Override public void eat () { System.out.println("狗正在吃骨头。" ); } } class Cat extends Animal { @Override public void eat () { System.out.println("猫正在吃鱼。" ); } } class PolymorphismDemo { public static void showPolymorphism () { Animal myDog = new Dog (); Animal myCat = new Cat (); myDog.eat(); myCat.eat(); } }
equals()
和 hashCode()
编写 Student
类,并重写 equals()
和 hashCode()
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import java.util.Objects;class Student { private int id; private String name; public Student (int id, String name) { this .id = id; this .name = name; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Student student = (Student) o; return id == student.id && Objects.equals(name, student.name); } @Override public int hashCode () { return Objects.hash(id, name); } }
接口与实现 (Interfaces and Implementation) 设计 Drawable
接口,并由 Circle
和 Rectangle
实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 interface Drawable { void draw () ; } class Circle implements Drawable { @Override public void draw () { System.out.println("正在画一个圆形。" ); } } class Rectangle implements Drawable { @Override public void draw () { System.out.println("正在画一个矩形。" ); } }
异常处理 (Exception Handling) 使用 try-catch-finally
结构处理 FileNotFoundException
并确保资源关闭。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;class ExceptionDemo { public static void processFile (String filePath) { FileInputStream fileInputStream = null ; try { fileInputStream = new FileInputStream (filePath); System.out.println("文件已成功打开。" ); } catch (FileNotFoundException e) { System.err.println("错误:指定的文件不存在!路径:" + filePath); e.printStackTrace(); } finally { if (fileInputStream != null ) { try { fileInputStream.close(); System.out.println("文件流已在 finally 块中关闭。" ); } catch (IOException e) { System.err.println("关闭文件流时发生异常:" + e.getMessage()); } } } } }
try-with-resources
使用 try-with-resources
重写上一个题目,展示其简化优势。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;class TryWithResourcesDemo { public static void processFileWithResources (String filePath) { try (FileInputStream fileInputStream = new FileInputStream (filePath)) { System.out.println("文件已成功打开。" ); } catch (FileNotFoundException e) { System.err.println("错误:指定的文件不存在!路径:" + filePath); e.printStackTrace(); } catch (IOException e) { System.err.println("关闭文件流时发生异常:" + e.getMessage()); } System.out.println("文件流已在 try-with-resources 语句中自动关闭。" ); } }
线程创建 1. 继承 Thread
类 通过继承 java.lang.Thread
类并重写其 run()
方法来创建线程。
1 2 3 4 5 6 7 8 class MyThread extends Thread { @Override public void run () { System.out.println("使用继承 Thread 类的方式创建的线程正在运行。" ); } }
2. 实现 Runnable
接口 通过实现 java.lang.Runnable
接口并将其作为参数传递给 Thread
类的构造函数来创建线程。这种方式更灵活,推荐使用。
1 2 3 4 5 6 7 8 class MyRunnable implements Runnable { @Override public void run () { System.out.println("使用实现 Runnable 接口的方式创建的线程正在运行。" ); } }
sleep()
与 yield()
sleep()
和 yield()
都是线程调度的方法,但它们的作用和效果不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class SleepYieldDemo { public static void main (String[] args) { new Thread (() -> { System.out.println("线程 A: 开始执行..." ); try { System.out.println("线程 A: 准备睡眠 2 秒..." ); Thread.sleep(2000 ); System.out.println("线程 A: 睡眠结束,继续执行。" ); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread (() -> { System.out.println("线程 B: 开始执行..." ); for (int i = 0 ; i < 5 ; i++) { System.out.println("线程 B: 正在执行 " + i); Thread.yield (); } System.out.println("线程 B: 执行完毕。" ); }).start(); } }
sleep() : 使当前线程暂停执行指定的时间 ,进入 TIMED_WAITING 状态。它会释放 CPU 资源 ,但不释放锁 。
yield() : 提示线程调度器,当前线程愿意让出当前 CPU 时间片 。线程会从 RUNNING 状态转换为 RUNNABLE 状态,与其他线程竞争 CPU,但不保证 其他线程能立即获得执行。它主要用于优化线程调度,通常在多线程程序中不应依赖 其行为来保证正确性。
join()
方法join()
方法允许一个线程等待另一个线程执行完毕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class JoinDemo { public static void main (String[] args) throws InterruptedException { Thread workerThread = new Thread (() -> { try { System.out.println("子线程: 正在执行..." ); Thread.sleep(3000 ); System.out.println("子线程: 执行完毕。" ); } catch (InterruptedException e) { e.printStackTrace(); } }); workerThread.start(); System.out.println("主线程: 等待子线程执行完毕..." ); workerThread.join(); System.out.println("主线程: 子线程已执行完毕,主线程继续执行。" ); } }
非线程安全计数器 在多线程环境下,多个线程同时对共享资源进行读写操作,可能导致数据不一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class UnsafeCounter { private int count = 0 ; public void increment () { count++; } public int getCount () { return count; } } class ThreadSafetyDemo { public static void main (String[] args) throws InterruptedException { UnsafeCounter counter = new UnsafeCounter (); Thread[] threads = new Thread [100 ]; for (int i = 0 ; i < threads.length; i++) { threads[i] = new Thread (() -> { for (int j = 0 ; j < 10000 ; j++) { counter.increment(); } }); threads[i].start(); } for (Thread thread : threads) { thread.join(); } System.out.println("非线程安全计数器的最终结果: " + counter.getCount()); } }
synchronized
关键字使用 synchronized
关键字可以保证同一时刻只有一个线程访问共享资源,从而解决线程安全问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class SynchronizedCounter { private int count = 0 ; public synchronized void increment () { count++; } public int getCount () { return count; } } class SynchronizedDemo { public static void main (String[] args) throws InterruptedException { SynchronizedCounter counter = new SynchronizedCounter (); Thread[] threads = new Thread [100 ]; for (int i = 0 ; i < threads.length; i++) { threads[i] = new Thread (() -> { for (int j = 0 ; j < 10000 ; j++) { counter.increment(); } }); threads[i].start(); } for (Thread thread : threads) { thread.join(); } System.out.println("synchronized 计数器的最终结果: " + counter.getCount()); } }
synchronized
块与方法
synchronized 方法 : 锁定的是当前对象实例 (this
)。
synchronized 块 : 提供了更细粒度的控制,可以指定锁定的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class SynchronizedBlockDemo { private final Object lock1 = new Object (); private final Object lock2 = new Object (); public synchronized void synchronizedMethod () { System.out.println(Thread.currentThread().getName() + " 进入 synchronized 方法。" ); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 离开 synchronized 方法。" ); } public void synchronizedBlock1 () { System.out.println(Thread.currentThread().getName() + " 尝试获取 lock1..." ); synchronized (lock1) { System.out.println(Thread.currentThread().getName() + " 已获取 lock1。" ); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 释放 lock1。" ); } } public void synchronizedBlock2 () { System.out.println(Thread.currentThread().getName() + " 尝试获取 lock2..." ); synchronized (lock2) { System.out.println(Thread.currentThread().getName() + " 已获取 lock2。" ); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 释放 lock2。" ); } } }
volatile
关键字volatile
关键字保证了变量在多线程间的可见性 ,但不保证原子性 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class VolatileDemo { private static volatile boolean ready = false ; public static void main (String[] args) throws InterruptedException { new Thread (() -> { System.out.println("线程 A: 正在等待标志位变为 true。" ); while (!ready) { } System.out.println("线程 A: 标志位已变为 true,循环结束。" ); }).start(); Thread.sleep(1000 ); System.out.println("主线程: 正在将标志位设置为 true。" ); ready = true ; } }
AtomicInteger
AtomicInteger
是一个原子类,它使用 CAS (Compare-and-Swap) 机制来保证操作的原子性,从而实现线程安全。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.concurrent.atomic.AtomicInteger;class AtomicCounter { private AtomicInteger count = new AtomicInteger (0 ); public void increment () { count.incrementAndGet(); } public int getCount () { return count.get(); } } class AtomicDemo { public static void main (String[] args) throws InterruptedException { AtomicCounter counter = new AtomicCounter (); Thread[] threads = new Thread [100 ]; for (int i = 0 ; i < threads.length; i++) { threads[i] = new Thread (() -> { for (int j = 0 ; j < 10000 ; j++) { counter.increment(); } }); threads[i].start(); } for (Thread thread : threads) { thread.join(); } System.out.println("AtomicInteger 计数器的最终结果: " + counter.getCount()); } }
线程通信 使用 wait()
和 notifyAll()
实现两个线程交替打印奇数和偶数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class PrintNumbers { private int count = 0 ; private final Object lock = new Object (); public void printOdd () { synchronized (lock) { while (count < 10 ) { while (count % 2 == 0 ) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ": " + count++); lock.notifyAll(); } } } public void printEven () { synchronized (lock) { while (count < 10 ) { while (count % 2 != 0 ) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ": " + count++); lock.notifyAll(); } } } public static void main (String[] args) { PrintNumbers pn = new PrintNumbers (); Thread oddThread = new Thread (pn::printOdd, "奇数线程" ); Thread evenThread = new Thread (pn::printEven, "偶数线程" ); oddThread.start(); evenThread.start(); } }
好的,以下是 中高级并发编程的实现,并附带详细注释。
生产者-消费者模式 (使用 wait()
和 notifyAll()
) 这是一个经典的线程协作问题。生产者生产数据,放入共享队列;消费者从队列中取出数据进行消费。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import java.util.LinkedList;import java.util.Queue;class ProducerConsumerClassic { private final Queue<Integer> queue = new LinkedList <>(); private final int MAX_SIZE = 5 ; private final Object LOCK = new Object (); public void produce () throws InterruptedException { int i = 0 ; while (true ) { synchronized (LOCK) { while (queue.size() == MAX_SIZE) { System.out.println("队列已满,生产者等待..." ); LOCK.wait(); } queue.offer(i); System.out.println("生产者生产了: " + i); i++; LOCK.notifyAll(); } Thread.sleep(100 ); } } public void consume () throws InterruptedException { while (true ) { synchronized (LOCK) { while (queue.isEmpty()) { System.out.println("队列为空,消费者等待..." ); LOCK.wait(); } int data = queue.poll(); System.out.println("消费者消费了: " + data); LOCK.notifyAll(); } Thread.sleep(500 ); } } }
生产者-消费者模式 (使用 BlockingQueue
) java.util.concurrent.BlockingQueue
接口提供了线程安全的队列操作,简化了生产者-消费者模型的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;class ProducerConsumerBlockingQueue { private final BlockingQueue<Integer> queue = new LinkedBlockingQueue <>(5 ); public void produce () throws InterruptedException { int i = 0 ; while (true ) { queue.put(i); System.out.println("生产者生产了: " + i); i++; Thread.sleep(100 ); } } public void consume () throws InterruptedException { while (true ) { int data = queue.take(); System.out.println("消费者消费了: " + data); Thread.sleep(500 ); } } }
ReentrantLock
使用 ReentrantLock
实现线程安全计数器,并解释其与 synchronized
的区别。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.concurrent.locks.ReentrantLock;class ReentrantLockCounter { private int count = 0 ; private final ReentrantLock lock = new ReentrantLock (); public void increment () { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount () { lock.lock(); try { return count; } finally { lock.unlock(); } } }
ReentrantLock
与 Condition
使用 ReentrantLock
和 Condition
重新实现生产者-消费者模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;class ProducerConsumerCondition { private final Queue<Integer> queue = new LinkedList <>(); private final int MAX_SIZE = 5 ; private final ReentrantLock lock = new ReentrantLock (); private final Condition producerCondition = lock.newCondition(); private final Condition consumerCondition = lock.newCondition(); public void produce () throws InterruptedException { int i = 0 ; while (true ) { lock.lock(); try { while (queue.size() == MAX_SIZE) { System.out.println("队列已满,生产者等待..." ); producerCondition.await(); } queue.offer(i); System.out.println("生产者生产了: " + i); i++; consumerCondition.signalAll(); } finally { lock.unlock(); } Thread.sleep(100 ); } } public void consume () throws InterruptedException { while (true ) { lock.lock(); try { while (queue.isEmpty()) { System.out.println("队列为空,消费者等待..." ); consumerCondition.await(); } int data = queue.poll(); System.out.println("消费者消费了: " + data); producerCondition.signalAll(); } finally { lock.unlock(); } Thread.sleep(500 ); } } }
ExecutorService
创建一个固定大小的线程池,并向其提交多个任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;class ExecutorServiceDemo { public static void main (String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3 ); for (int i = 0 ; i < 10 ; i++) { final int taskId = i; executorService.execute(() -> { System.out.println("任务 " + taskId + " 正在由线程 " + Thread.currentThread().getName() + " 执行。" ); try { Thread.sleep(1000 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } executorService.shutdown(); } }
Callable
与 Future
使用 Callable
提交任务,并使用 Future
获取返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.concurrent.*;class CallableFutureDemo { public static void main (String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Callable<String> task = () -> { System.out.println("任务开始执行..." ); Thread.sleep(2000 ); return "任务执行完毕,返回结果!" ; }; Future<String> future = executorService.submit(task); System.out.println("主线程: 任务已提交,继续执行其他操作..." ); String result = future.get(); System.out.println("主线程: 获得任务结果 -> " + result); executorService.shutdown(); } }
CountDownLatch
CountDownLatch
允许一个或多个线程等待直到在其他线程中执行的一组操作完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;class CountDownLatchDemo { public static void main (String[] args) throws InterruptedException { int workerCount = 5 ; CountDownLatch latch = new CountDownLatch (workerCount); ExecutorService executor = Executors.newFixedThreadPool(workerCount); for (int i = 0 ; i < workerCount; i++) { final int workerId = i; executor.execute(() -> { System.out.println("工作线程 " + workerId + " 开始执行任务..." ); try { Thread.sleep((long ) (Math.random() * 2000 )); System.out.println("工作线程 " + workerId + " 任务完成。" ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { latch.countDown(); } }); } System.out.println("主线程: 等待所有工作线程完成..." ); latch.await(); System.out.println("主线程: 所有工作线程已完成,继续执行下一步。" ); executor.shutdown(); } }
CyclicBarrier
CyclicBarrier
允许一组线程相互等待,直到所有线程都到达一个共同的屏障点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;class CyclicBarrierDemo { public static void main (String[] args) { int partySize = 3 ; CyclicBarrier barrier = new CyclicBarrier (partySize, () -> { System.out.println("\n所有线程已到达屏障点!继续执行下一阶段。\n" ); }); ExecutorService executor = Executors.newFixedThreadPool(partySize); for (int i = 0 ; i < partySize; i++) { final int threadId = i; executor.execute(() -> { try { System.out.println("线程 " + threadId + " 正在执行第一阶段任务..." ); Thread.sleep((long ) (Math.random() * 1000 )); System.out.println("线程 " + threadId + " 第一阶段任务完成,到达屏障。" ); barrier.await(); System.out.println("线程 " + threadId + " 正在执行第二阶段任务..." ); } catch (InterruptedException | BrokenBarrierException e) { Thread.currentThread().interrupt(); } }); } executor.shutdown(); } }
Semaphore
Semaphore
(信号量)用来控制对资源的并发访问数量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.util.concurrent.Semaphore;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;class SemaphoreDemo { private final Semaphore semaphore = new Semaphore (3 ); public void accessResource (int threadId) { try { semaphore.acquire(); System.out.println("线程 " + threadId + " 正在访问资源..." ); Thread.sleep(2000 ); System.out.println("线程 " + threadId + " 访问资源完毕。" ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); } } public static void main (String[] args) { SemaphoreDemo demo = new SemaphoreDemo (); ExecutorService executor = Executors.newFixedThreadPool(10 ); for (int i = 0 ; i < 10 ; i++) { final int threadId = i; executor.execute(() -> demo.accessResource(threadId)); } executor.shutdown(); } }
线程死锁 1. 死锁演示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class DeadlockDemo { private static final Object lock1 = new Object (); private static final Object lock2 = new Object (); public void threadA () { synchronized (lock1) { System.out.println("线程A: 已获得 lock1,尝试获取 lock2..." ); try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { System.out.println("线程A: 已获得 lock2。" ); } } } public void threadB () { synchronized (lock2) { System.out.println("线程B: 已获得 lock2,尝试获取 lock1..." ); try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1) { System.out.println("线程B: 已获得 lock1。" ); } } } public static void main (String[] args) { DeadlockDemo demo = new DeadlockDemo (); new Thread (demo::threadA, "Thread-A" ).start(); new Thread (demo::threadB, "Thread-B" ).start(); } }
死锁预防 通过打破死锁的四个必要条件之一来预防死锁。这里通过资源有序分配 来打破循环等待 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class DeadlockPrevention { private static final Object lock1 = new Object (); private static final Object lock2 = new Object (); public void threadA () { synchronized (lock1) { System.out.println("线程A: 已获得 lock1,尝试获取 lock2..." ); synchronized (lock2) { System.out.println("线程A: 已获得 lock2。" ); } } } public void threadB () { synchronized (lock1) { System.out.println("线程B: 已获得 lock1,尝试获取 lock2..." ); synchronized (lock2) { System.out.println("线程B: 已获得 lock2。" ); } } } public static void main (String[] args) { DeadlockPrevention demo = new DeadlockPrevention (); new Thread (demo::threadA, "Thread-A" ).start(); new Thread (demo::threadB, "Thread-B" ).start(); } }
ThreadLocal
ThreadLocal
为每个线程提供了一个独立的变量副本,实现了线程间的数据隔离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class ThreadLocalDemo { private static final ThreadLocal<String> threadLocal = new ThreadLocal <>(); public void setAndPrint (String value) { threadLocal.set(value); try { Thread.sleep(1000 ); System.out.println(Thread.currentThread().getName() + " 的变量值: " + threadLocal.get()); } catch (InterruptedException e) { e.printStackTrace(); } finally { threadLocal.remove(); } } public static void main (String[] args) { ThreadLocalDemo demo = new ThreadLocalDemo (); new Thread (() -> demo.setAndPrint("线程 A 的数据" ), "Thread-A" ).start(); new Thread (() -> demo.setAndPrint("线程 B 的数据" ), "Thread-B" ).start(); } }
线程安全单例 (静态内部类) 静态内部类方式是实现线程安全的懒汉式单例的最佳实践之一。它利用了 JVM 类加载机制的线程安全特性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class SingletonThreadSafe { private SingletonThreadSafe () {} private static class SingletonHolder { private static final SingletonThreadSafe INSTANCE = new SingletonThreadSafe (); } public static SingletonThreadSafe getInstance () { return SingletonHolder.INSTANCE; } }
ReadWriteLock
ReadWriteLock
适用于读多写少的场景,它允许多个线程同时进行读操作,但写操作必须是互斥的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;class ReadWriteLockDemo { private final ReadWriteLock rwLock = new ReentrantReadWriteLock (); private final Object sharedData = "初始数据" ; public String readData () { rwLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " 正在读取数据..." ); Thread.sleep(1000 ); return (String) sharedData; } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null ; } finally { rwLock.readLock().unlock(); } } public void writeData (String newData) { rwLock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " 正在写入数据..." ); Thread.sleep(2000 ); System.out.println(Thread.currentThread().getName() + " 写入完成。" ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { rwLock.writeLock().unlock(); } } }
线程池关闭 ExecutorService
的两种关闭方式:shutdown()
和 shutdownNow()
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;class ShutdownDemo { public static void main (String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2 ); for (int i = 0 ; i < 5 ; i++) { final int taskId = i; executor.execute(() -> { try { System.out.println("任务 " + taskId + " 正在执行..." ); Thread.sleep(2000 ); } catch (InterruptedException e) { System.out.println("任务 " + taskId + " 被中断。" ); } }); } executor.shutdownNow(); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程池已关闭。" ); } }
中断机制 一个线程通过响应 interrupt()
调用来正确停止自身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class InterruptedThreadDemo { public static void main (String[] args) { Thread worker = new Thread (() -> { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("线程正在执行..." ); Thread.sleep(1000 ); } catch (InterruptedException e) { System.out.println("线程被中断!" ); Thread.currentThread().interrupt(); return ; } } System.out.println("线程已退出。" ); }); worker.start(); try { Thread.sleep(3500 ); } catch (InterruptedException e) { e.printStackTrace(); } worker.interrupt(); } }
死锁预防 (按锁顺序) 通过资源有序分配 来打破死锁的循环等待 条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class DeadlockPrevention { private static final Object lockA = new Object (); private static final Object lockB = new Object (); public void threadOne () { synchronized (lockA) { System.out.println("线程 1: 已获得 lockA,尝试获取 lockB..." ); try { Thread.sleep(100 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } synchronized (lockB) { System.out.println("线程 1: 已获得 lockB。" ); } } } public void threadTwo () { synchronized (lockA) { System.out.println("线程 2: 已获得 lockA,尝试获取 lockB..." ); try { Thread.sleep(100 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } synchronized (lockB) { System.out.println("线程 2: 已获得 lockB。" ); } } } public static void main (String[] args) { DeadlockPrevention demo = new DeadlockPrevention (); new Thread (demo::threadOne, "Thread-1" ).start(); new Thread (demo::threadTwo, "Thread-2" ).start(); } }
线程池异常 使用 Future.get()
或在任务中捕获异常来处理线程池中任务抛出的异常。execute()
方法无法直接捕获异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import java.util.concurrent.*;class ThreadPoolExceptionDemo { public static void main (String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(2 ); Future<?> future = executor.submit(() -> { System.out.println("任务开始执行..." ); throw new RuntimeException ("这是一个模拟的任务执行异常。" ); }); try { future.get(); } catch (ExecutionException e) { System.err.println("捕获到任务执行异常:" + e.getCause().getMessage()); } executor.execute(() -> { System.out.println("另一个任务开始执行..." ); throw new IllegalArgumentException ("这个异常会被吞掉。" ); }); executor.shutdown(); executor.awaitTermination(1 , TimeUnit.SECONDS); } }
ThreadLocal
ThreadLocal
为每个线程提供了独立的变量副本,实现了数据隔离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class ThreadLocalDemo { private static final ThreadLocal<String> threadLocal = new ThreadLocal <>(); public void setAndPrint (String value) { threadLocal.set(value); try { Thread.sleep(1000 ); System.out.println(Thread.currentThread().getName() + " 的变量值: " + threadLocal.get()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { threadLocal.remove(); } } public static void main (String[] args) { ThreadLocalDemo demo = new ThreadLocalDemo (); new Thread (() -> demo.setAndPrint("线程 A 的数据" ), "Thread-A" ).start(); new Thread (() -> demo.setAndPrint("线程 B 的数据" ), "Thread-B" ).start(); } }
LockSupport
LockSupport.park()
和 LockSupport.unpark()
提供了更灵活的线程阻塞和唤醒机制,类似于 wait()
和 notify()
,但不需要依赖锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.concurrent.locks.LockSupport;class LockSupportDemo { public static void main (String[] args) throws InterruptedException { Thread workerThread = new Thread (() -> { System.out.println("工作线程: 任务准备就绪,即将阻塞..." ); LockSupport.park(); System.out.println("工作线程: 被唤醒,继续执行。" ); }); workerThread.start(); Thread.sleep(2000 ); System.out.println("主线程: 唤醒工作线程。" ); LockSupport.unpark(workerThread); } }
线程通信 (按顺序打印) 使用 wait()
和 notifyAll()
实现三个线程按顺序打印。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class SequentialPrinter { private int state = 0 ; private final Object lock = new Object (); public void printA () { printLetter("A" , 0 ); } public void printB () { printLetter("B" , 1 ); } public void printC () { printLetter("C" , 2 ); } private void printLetter (String letter, int expectedState) { for (int i = 0 ; i < 10 ; i++) { synchronized (lock) { while (state != expectedState) { try { lock.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return ; } } System.out.print(letter); state = (state + 1 ) % 3 ; lock.notifyAll(); } } } public static void main (String[] args) throws InterruptedException { SequentialPrinter printer = new SequentialPrinter (); Thread threadA = new Thread (printer::printA); Thread threadB = new Thread (printer::printB); Thread threadC = new Thread (printer::printC); threadA.start(); threadB.start(); threadC.start(); threadA.join(); threadB.join(); threadC.join(); System.out.println("\n打印完成。" ); } }
线程池 ThreadPoolExecutor
的七个参数
corePoolSize
: 核心线程数。线程池中常驻的线程数量,即使空闲也不会被销毁。
maximumPoolSize
: 最大线程数。当工作队列已满,且任务量继续增加时,线程池可以创建的最大线程数。
keepAliveTime
: 空闲线程存活时间。当线程数大于 corePoolSize
时,非核心线程的空闲存活时间。
unit
: keepAliveTime
的时间单位。
workQueue
: 工作队列。用于存放等待执行的任务,常用的有 ArrayBlockingQueue
、LinkedBlockingQueue
等。
threadFactory
: 线程工厂。用于创建新线程,可以自定义线程的名称、优先级等。
handler
: 拒绝策略。当线程池和工作队列都已满时,用于处理新来的任务,例如抛出异常、由调用者执行等。
手写一个自定义线程池 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import java.util.concurrent.*;public class CustomThreadPool { public static void main (String[] args) { ExecutorService executor = new ThreadPoolExecutor ( 2 , 5 , 60L , TimeUnit.SECONDS, new LinkedBlockingQueue <>(10 ), Executors.defaultThreadFactory(), new ThreadPoolExecutor .CallerRunsPolicy() ); for (int i = 0 ; i < 20 ; i++) { final int taskId = i; executor.execute(() -> { System.out.println("任务 " + taskId + " 正在由线程 " + Thread.currentThread().getName() + " 执行。" ); try { Thread.sleep(100 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } executor.shutdown(); } }
原子类 使用 AtomicBoolean
或 AtomicReference
解决并发问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.concurrent.atomic.AtomicBoolean;class AtomicBooleanDemo { private static final AtomicBoolean initialized = new AtomicBoolean (false ); public static void initialize () { if (initialized.compareAndSet(false , true )) { System.out.println(Thread.currentThread().getName() + ": 开始执行初始化操作..." ); try { Thread.sleep(1000 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println(Thread.currentThread().getName() + ": 初始化完成。" ); } else { System.out.println(Thread.currentThread().getName() + ": 初始化已被其他线程执行,跳过。" ); } } public static void main (String[] args) { for (int i = 0 ; i < 5 ; i++) { new Thread (AtomicBooleanDemo::initialize, "Thread-" + i).start(); } } }
volatile
内存语义volatile
确保了可见性 和有序性 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class VolatileMemorySemantics { private static volatile boolean ready = false ; private static int number = 0 ; public static class WriterThread extends Thread { @Override public void run () { number = 42 ; ready = true ; } } public static class ReaderThread extends Thread { @Override public void run () { while (!ready) { } System.out.println("读取到的 number 值: " + number); } } public static void main (String[] args) throws InterruptedException { new WriterThread ().start(); new ReaderThread ().start(); } }
中断机制 一个线程通过响应 interrupt()
调用来正确停止自身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class InterruptibleThreadDemo { public static void main (String[] args) { Thread worker = new Thread (() -> { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("线程正在执行..." ); Thread.sleep(1000 ); } catch (InterruptedException e) { System.out.println("线程被中断,即将退出..." ); Thread.currentThread().interrupt(); break ; } } System.out.println("线程已优雅地退出。" ); }); worker.start(); try { Thread.sleep(3500 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("主线程: 发送中断信号。" ); worker.interrupt(); } }
ConcurrentHashMap
ConcurrentHashMap
的并发原理是**分段锁( 7)**或 CAS + Synchronized( 8) ,只对操作的桶进行锁定,大大提高了并发性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;class ConcurrentHashMapDemo { public static void main (String[] args) throws InterruptedException { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap <>(); ExecutorService executor = Executors.newFixedThreadPool(10 ); for (int i = 0 ; i < 10 ; i++) { final int threadId = i; executor.execute(() -> { for (int j = 0 ; j < 1000 ; j++) { String key = "key-" + (threadId * 1000 + j); map.put(key, j); } }); } executor.shutdown(); executor.awaitTermination(1 , TimeUnit.MINUTES); System.out.println("最终 map 的大小: " + map.size()); } }
ForkJoinPool
ForkJoinPool
是一个用于分治任务的线程池,RecursiveTask
是可返回结果的分治任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;class SumTask extends RecursiveTask <Long> { private final long [] array; private final int start; private final int end; private static final int THRESHOLD = 10000 ; public SumTask (long [] array, int start, int end) { this .array = array; this .start = start; this .end = end; } @Override protected Long compute () { if (end - start <= THRESHOLD) { long sum = 0 ; for (int i = start; i < end; i++) { sum += array[i]; } return sum; } else { int mid = start + (end - start) / 2 ; SumTask leftTask = new SumTask (array, start, mid); SumTask rightTask = new SumTask (array, mid, end); leftTask.fork(); long rightResult = rightTask.compute(); long leftResult = leftTask.join(); return leftResult + rightResult; } } public static void main (String[] args) { long [] array = new long [1000000 ]; for (int i = 0 ; i < array.length; i++) { array[i] = i; } ForkJoinPool pool = new ForkJoinPool (); SumTask task = new SumTask (array, 0 , array.length); long result = pool.invoke(task); System.out.println("大数组的和为: " + result); pool.shutdown(); } }
1. 语言基础 变量与数据类型 的基本数据类型决定了变量可以存储的数据范围。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class DataTypesDetailed { public static void main (String[] args) { byte b = 100 ; short s = 10000 ; int i = 100000 ; long l = 10000000000L ; float f = 3.14f ; double d = 3.1415926535 ; char c1 = 'A' ; char c2 = 65 ; System.out.println("c1 和 c2 是否相等? " + (c1 == c2)); boolean isFun = true ; System.out.println("学Java有趣吗?" + isFun); } }
类型转换 中,从小范围类型向大范围类型转换是自动 的(隐式转换);从大范围向小范围转换需要强制 转换(显式转换),可能造成数据丢失。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class TypeCasting { public static void main (String[] args) { int myInt = 100 ; long myLong = myInt; System.out.println("隐式转换后的 long 类型: " + myLong); double myDouble = 9.99 ; int myInteger = (int ) myDouble; System.out.println("显式转换后的 int 类型: " + myInteger); } }
数组 数组是存储固定大小 同类型元素的集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class ArrayExample { public static void main (String[] args) { int [] numbers = new int [5 ]; numbers[0 ] = 10 ; numbers[1 ] = 20 ; String[] fruits = {"Apple" , "Banana" , "Cherry" }; System.out.println("所有水果:" ); for (String fruit : fruits) { System.out.println(fruit); } } }
2. 面向对象编程 (OOP) 构造方法与方法重载 构造方法 是一种特殊方法,用于创建对象时初始化。方法重载 是指在同一个类中,方法名相同但参数列表不同(参数类型、数量或顺序)的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class Student { String name; int age; String id; public Student () { this ("未知" , 0 , "000" ); } public Student (String name, int age) { this .name = name; this .age = age; this .id = "000" ; } public Student (String name, int age, String id) { this .name = name; this .age = age; this .id = id; } public int add (int a, int b) { return a + b; } public double add (double a, double b) { return a + b; } }
继承、多态与抽象 继承实现代码复用,多态实现行为多样化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 abstract class Vehicle { protected String brand; public Vehicle (String brand) { this .brand = brand; } public abstract void run () ; public void displayBrand () { System.out.println("品牌是: " + brand); } } class Car extends Vehicle { public Car (String brand) { super (brand); } @Override public void run () { System.out.println("汽车正在路上行驶..." ); } } class Bicycle extends Vehicle { public Bicycle (String brand) { super (brand); } @Override public void run () { System.out.println("自行车正在骑行..." ); } } public class PolymorphismDemo { public static void main (String[] args) { Vehicle myCar = new Car ("BMW" ); Vehicle myBicycle = new Bicycle ("Giant" ); myCar.run(); myBicycle.run(); } }
3. 核心类库 好的,这次我们将把各种方法的使用代码 直接嵌入到每个知识点的解释中,让您在学习概念的同时,就能看到具体的代码实现和效果。我们将专注于数组、字符串和集合 这三大核心部分,把它们的创建、遍历、和各种常用方法的代码示例都清晰地展示出来。
1. 数组(Array) 数组是一种固定大小的、用于存储同类型元素的容器。
创建和遍历 这里展示两种最常见的创建数组的方式,并使用两种循环进行遍历。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.Arrays;public class ArrayExample { public static void main (String[] args) { int [] intArray = new int [3 ]; intArray[0 ] = 10 ; intArray[1 ] = 20 ; intArray[2 ] = 30 ; System.out.println("数组 intArray 的第一个元素是: " + intArray[0 ]); String[] stringArray = {"Hello" , "World" , "Java" }; System.out.println("\n--- 使用 for 循环遍历 ---" ); for (int i = 0 ; i < stringArray.length; i++) { System.out.println("stringArray[" + i + "] = " + stringArray[i]); } System.out.println("\n--- 使用增强 for 循环遍历 ---" ); for (String element : stringArray) { System.out.println("元素: " + element); } } }
Arrays
类的常用方法java.util.Arrays
类提供了很多静态方法,方便我们对数组进行操作,比如排序、查找、复制等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.Arrays;public class ArraysMethodExample { public static void main (String[] args) { int [] numbers = {4 , 2 , 8 , 1 , 6 }; Arrays.sort(numbers); System.out.println("排序后: " + Arrays.toString(numbers)); int index = Arrays.binarySearch(numbers, 6 ); System.out.println("元素 6 的索引是: " + index); int [] newArray = new int [5 ]; Arrays.fill(newArray, 99 ); System.out.println("填充后: " + Arrays.toString(newArray)); int [] copiedArray = Arrays.copyOf(numbers, 3 ); System.out.println("复制前3个元素: " + Arrays.toString(copiedArray)); int [] anotherArray = {1 , 2 , 4 , 6 , 8 }; System.out.println("两个数组是否相等: " + Arrays.equals(numbers, anotherArray)); } }
2. 字符串(String) String
是一个不可变的字符序列,这意味着一旦创建,它的内容就不能被修改。所有修改操作都会返回一个新的 String
对象。
创建和常用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class StringExample { public static void main (String[] args) { String str1 = " Java is a great language. " ; String str2 = new String ("Java is a great language." ); int length = str1.length(); System.out.println("字符串长度: " + length); char firstChar = str1.charAt(2 ); System.out.println("第3个字符是: " + firstChar); String sub = str1.substring(5 , 7 ); System.out.println("截取子串: " + sub); int index = str1.indexOf("great" ); System.out.println("'great' 的索引: " + index); boolean contains = str1.contains("language" ); System.out.println("是否包含 'language': " + contains); boolean startsWith = str1.startsWith(" Java" ); System.out.println("是否以 ' Java' 开头: " + startsWith); String replacedStr = str1.replace("great" , "wonderful" ); System.out.println("替换后: " + replacedStr); String trimmedStr = str1.trim(); System.out.println("去除首尾空格: '" + trimmedStr + "'" ); System.out.println("转为大写: " + trimmedStr.toUpperCase()); String data = "apple,banana,orange" ; String[] fruits = data.split("," ); System.out.println("分割后: " + Arrays.toString(fruits)); String joinedString = String.join(" - " , fruits); System.out.println("连接后: " + joinedString); } }
StringBuilder
和 StringBuffer
对于需要频繁修改字符串的场景,应使用 StringBuilder
或 StringBuffer
以提高性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class StringBuilderExample { public static void main (String[] args) { StringBuilder sb = new StringBuilder ("Hello" ); sb.append(" World" ); System.out.println("追加后: " + sb); sb.insert(6 , "Beautiful " ); System.out.println("插入后: " + sb); sb.delete(6 , 15 ); System.out.println("删除后: " + sb); } }
3. 集合(Collections) Java 集合框架提供了强大的数据结构来存储和操作对象。
List (列表)List
是一种有序、可重复的集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.ArrayList;import java.util.LinkedList;import java.util.List;public class ListExample { public static void main (String[] args) { List<String> fruits = new ArrayList <>(); fruits.add("Apple" ); fruits.add("Banana" ); fruits.add("Apple" ); System.out.println("列表元素: " + fruits); System.out.println("第一个元素: " + fruits.get(0 )); System.out.println("列表大小: " + fruits.size()); fruits.set(1 , "Grape" ); System.out.println("替换后: " + fruits); fruits.remove(1 ); System.out.println("删除后: " + fruits); } }
Set (集)Set
是一种无序、不可重复的集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.HashSet;import java.util.Set;public class SetExample { public static void main (String[] args) { Set<String> uniqueFruits = new HashSet <>(); uniqueFruits.add("Apple" ); uniqueFruits.add("Banana" ); uniqueFruits.add("Apple" ); System.out.println("集合元素: " + uniqueFruits); boolean containsBanana = uniqueFruits.contains("Banana" ); System.out.println("是否包含 'Banana': " + containsBanana); uniqueFruits.remove("Banana" ); System.out.println("删除后: " + uniqueFruits); } }
Map (映射)Map
存储键值对,键是唯一的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.util.HashMap;import java.util.Map;public class MapExample { public static void main (String[] args) { Map<String, Integer> studentScores = new HashMap <>(); studentScores.put("Alice" , 95 ); studentScores.put("Bob" , 88 ); studentScores.put("Alice" , 100 ); System.out.println("Alice 的分数: " + studentScores.get("Alice" )); System.out.println("\n--- 遍历键集 ---" ); for (String name : studentScores.keySet()) { System.out.println("姓名: " + name + ", 分数: " + studentScores.get(name)); } System.out.println("\n--- 遍历值集 ---" ); for (Integer score : studentScores.values()) { System.out.println("分数: " + score); } System.out.println("\n--- 遍历键值对集 ---" ); for (Map.Entry<String, Integer> entry : studentScores.entrySet()) { System.out.println("姓名: " + entry.getKey() + ", 分数: " + entry.getValue()); } } }