7月24日JavaSE学习笔记

序列化版本控制

序列化:将内存对象转换成序列(流)的过程

反序列化:将对象序列读入程序,转换成对象的方式;反序列化的对象是一个新的对象

serialVersionUID 是一个类的序列化版本号

    private static final long serialVersionUID=1L;//版本号

如果序列化版本号没有定义,JDK会自动给予一个版本号,当该类发生变化时,序列化版本号会发生变化,反序列化就会失败;

java.io.InvalidClassException: com.easy724.Student; local class incompatible: stream classdesc serialVersionUID = -8506049007973969582, local class serialVersionUID = -401684047259788573

自定义版本号,只要该版本号不发生变化,即使该类中的属性或方法发生改变,该类的对象依旧可以反序列化。

注意:想要序列化,必须该类中的所有对象都是可序列化的(实现Serializable接口)


transient 关键字:暂存,禁止属性的值被序列化

    //transient 暂存,禁止属性的值被序列化private transient String sex;


flush方法

flush方法用于将输出流中的缓冲区内容立即写入目标设备,使得数据能够及时发送出去。

在Java中,几乎所有的输出流都具有flush方法。调用flush方法会强制将缓冲区中的数据写入目标设备,而不需要等到缓冲区被填满或者关闭流时才进行写入操作。

在使用输出流写入数据时,如果没有调用flush方法,写入的数据会先被缓存到缓冲区中,待到缓冲区填满或者手动调用flush方法时才会写入目标设备。但是,在某些情况下,我们需要立即将数据发送出去,例如需要实时更新数据时,可以调用flush方法来实现。

所有的输出流在结束之前都要执行一遍flush()方法


BIO、NIO、AIO

BIO、NIO、AIO 是 Java 编程语言中用于处理网络通信的三种不同的 I/O 模型。

BIO(Blocking I/O)是传统的同步阻塞式 I/O 模型。在这种模型中,每个连接都要创建一个线程进行处理,当有大量连接时,会导致线程数过多,资源消耗增加。

NIO(Non-blocking I/O)是一种基于事件驱动的同步非阻塞 I/O 模型。在这种模型中,I/O 操作不会阻塞线程,而是将 I/O 事件通知给选择器(Selector),然后通过一个或多个线程来处理这些事件。

AIO(Asynchronous I/O)是一种异步非阻塞 I/O 模型。它将数据的读写操作交给操作系统内核来处理,不需要通过线程池或者线程来阻塞等待结果,而是在操作完成后通过回调函数的方式来将数据返回给应用程序。

在高并发的场景下,NIO 和 AIO 的性能会比 BIO 更好。

同步与异步的区别在于:
同步:请求与响应同时进行,直到响应再返回结果;
异步:请求直接返回空结果,不会立即响应,但一定会有响应,通过通知、状态、回调函数响应

阻塞与非阻塞的区别在于:
阻塞:请求后一直等待
非阻塞:请求后,可以继续干其他事,直到响应


线程 Thread类

线程是指计算机中能够执行独立任务的最小单位。它是进程的一部分,一个进程可以包含多个线程。每个线程都是独立运行的,它们共享进程的资源,如内存空间和文件句柄等。线程之间可以通过共享内存进行通信,因此线程之间的切换开销较小。

进程是计算机中执行任务的基本单位,它是程序在执行过程中的一个实例。一个进程可以包含多个线程,每个线程执行不同的任务。进程之间是独立的,它们有自己独立的地址空间和资源。进程之间的通信需要经过额外的机制,如管道、消息队列等。

总结来说,线程是进程的一部分,是计算机中执行任务的最小单位。进程负责管理和分配资源,线程负责具体的任务执行。线程之间共享进程的资源,进程之间需要通过额外的机制进行通信。

常用方法

自定义线程 继承Thread,重写run方法,定义线程要执行的任务

子类抛出的异常只能比父类更精确,父类没有异常,子类的run不能抛出,要处理

1. 获取当前线程对象Thread.currentThread()

class ThreadA extends Thread{//重写run方法,定义线程要执行的任务@Overridepublic void run(){for (int i=0;i<=20;i++){System.out.println(i+Thread.currentThread().getName());}}
}

2. 开启线程 start()

        //实例化线程对象ThreadA a = new ThreadA();ThreadA b = new ThreadA();//开启线程,多线程可能交叉执行a.start();b.start();//普通对象调用方法,通过main主线程依次执行
//        a.run();
//        b.run();

3. 休眠的方法 sleep()

sleep 是一个Thread类的静态方法,传入一个long类型的参数表示当线程运行到这里时要休眠多少毫秒,休眠结束后会自动启动线程。

    //休眠的方法 sleeppublic static void threadSleep() throws InterruptedException {System.out.println("1---------");//让运行到该行代码的线程休眠5秒Thread.sleep(5000);System.out.println("2---------");}

4. 设置优先级 setPriority()

优先级最小为1,最大为10,默认5;

优先级越高,获取CUP资源(时间片)的几率越大

并不是谁的优先级高就执行谁,也会出现交叉

    public static void priority(){Thread a=new ThreadB();Thread b=new ThreadB();//设置优先级:最大10,最小1,默认5    设置其他值报非法参数异常a.setPriority(4);b.setPriority(6);//优先级越高,获取CUP资源的几率越大(时间片)a.start();b.start();}

5. 礼让 yield

作用:让出CPU资源,让CPU重新分配;

防止一条线程长时间占用资源,达到CPU合理分配的效果;

sleep(0)也可以达到重新分配CPU资源的效果

    @Overridepublic void run(){for(int i=0;i<20;i++){if(i%3==0){System.out.println(this.getName()+"---执行了礼让");Thread.yield();}System.out.println(i+this.getName());}}

6. 加入(插队)join()

在A线程中执行了B.join(),B线程运行完毕,A线程再运行

    @Overridepublic void run(){for(int i=0;i<200;i++){if(i==10&&t!=null&&t.isAlive()){System.out.println(this.getName()+"----执行了JION");try {t.join();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(i+this.getName());}}

关闭线程:

1.执行stop方法 不推荐

2.调用interrupt()设置中断状态,这个线程不会直接中断, 我们需要在线程内部通过isInterrupted判断中断状态是否被设置,然后执行中断操作

    @Overridepublic void run(){for(int i=0;i<100;i++){if(Thread.currentThread().isInterrupted()){//判断中断状态break;}try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(i);}}

3.自定义一个状态属性,在线程外部设置此属性,影响线程内部的运行

class ThreadG extends Thread{volatile boolean stop=false;//不稳定的,声明这个属性的值可能发生变化@Overridepublic void run(){while (!stop){//System.out.println("A");}}
}

这里需要用到volatile关键字:不稳定的,易变的,声明这个属性的值可能发生变化

volatile关键字用于修饰变量,表示该变量是易变的(volatile变量)。当一个变量被声明为volatile时,它会告知编译器和虚拟机该变量可能会被多个线程同时访问并修改,因此需要特别注意线程可见性和指令重排序等问题。

对于使用了volatile修饰的变量,在线程外部对其进行修改后,其他线程在访问该变量时能够立即看到最新的值,而不会使用缓存中的旧值。

使用volatile关键字的一个常见应用场景是用于控制线程的停止标志。例如,我们可以定义一个volatile变量作为线程的停止标志,在外部设置该变量的值为true时,线程内部通过检查该变量的值来决定是否停止执行。

    public static void stopThread(){ThreadG a = new ThreadG();a.start();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}a.stop = true;System.out.println("设置关闭");}

volatile关键字在多线程编程中起到了两个主要作用:

  1. 可见性:如果一个变量被声明为volatile,当一个线程修改了该变量的值,其他线程可以立即看到变量的最新值。普通的变量在多线程环境下可能存在数据不一致的问题,因为线程A修改了变量的值,但是线程B在此之前已经缓存了该变量的旧值,导致线程B读取的是一个过期的值。使用volatile关键字可以避免这种情况发生,保证变量的可见性。

  2. 有序性:普通的变量在多线程环境下可能存在指令重排序的问题。指令重排序是指处理器为了提高执行效率,可能会对指令进行重新排序执行,但是重排序可能会导致代码的执行顺序与预期不一致。使用volatile关键字可以禁止指令重排序,保证代码的执行顺序与程序员编写的顺序一致

需要使用volatile关键字的主要原因是多线程环境下的可见性和有序性问题。在多线程编程中,为了保证数据的一致性和正确性,需要使用volatile关键字来解决这些问题。


线程的生命周期

线程的生命周期可以简要概括为以下几个状态:

  1. 新建(New):线程被创建但尚未开始执行。
  2. 就绪(Runnable):线程处于可运行状态,等待被分配CPU时间片以执行。此时可能有多个线程处于就绪状态,但只有一个线程能够获得CPU时间片执行。
  3. 运行(Running):线程获得了CPU时间片,正在执行线程体中的代码。
  4. 阻塞(Blocked):线程因为某些原因被阻塞,暂时停止执行。可能的原因包括等待某个操作完成、等待输入/输出、等待锁等。当阻塞条件满足时,线程会重新进入就绪状态。
  5. 等待(Waiting):线程因为调用了wait()方法,主动让出CPU并进入等待状态,直到其他线程调用了相同对象的notify()notifyAll()方法才能被唤醒。
  6. 超时等待(Timed Waiting):线程因为调用了带有超时参数的wait()join()sleep()方法,进入具有超时等待时间的等待状态。当超时时间到达或其他线程唤醒它时,线程会重新进入就绪状态。
  7. 终止(Terminated):线程执行完了所有的代码或者出现了未捕获的异常而意外终止。

线程安全

线程安全是多个线程操作一个对象,不会出现结果错乱的情况(不是指顺序不一致,是结果缺失)

同步(Synchronous)指的是线程按照顺序依次执行,前一个线程执行完毕后,下一个线程才能开始执行同步可以保证线程之间的操作按照一定的顺序和规则进行,从而避免竞争条件和数据不一致的问题。常用的同步机制包括使用锁(如synchronized关键字)、信号量、互斥量等。

异步(Asynchronous)指的是线程在执行任务时,不需要等待上一个任务的完成,而是同时执行多个任务。异步通常通过回调函数、事件驱动等方式实现。异步执行可以提高程序的性能和响应速度,但也需要考虑线程安全问题。

StringBuilder是线程不安全的,StringBuffer是线程安全的

//实现Runnable接口,是实现线程的一种方式,是一个任务,不是线程类
class RunA implements Runnable{StringBuffer strB;public RunA(StringBuffer strB){this.strB = strB;}@Overridepublic void run() {for(int i=0;i<1000;i++){strB.append("0");}}
}

不继承Thread,通过实现Runnable接口也可以使用线程操作运行。

  1. 通过传入Runnable接口实现类的对象,可以将多个线程所需执行的任务抽象为一个统一的接口,避免了重复编写相同的代码。可以让多个线程对同一个对象操作。

  2. 在Java中,一个类只能继承自一个父类,但是可以实现多个接口。通过传入Runnable接口实现类对象,可以将线程任务类继承自其他的类,并且实现Runnable接口,提高灵活性。
        StringBuffer strB = new StringBuffer();RunA r=new RunA(strB);Thread a=new Thread(r);a.start();Thread b=new Thread(r);b.start();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(strB.length());}

StringBuilder当多个线程同时操作时,可能出现同时操作数组同一个位置的情况,导致数据缺失。

StringBuffer中的方法用synchronized修饰,同一时间内只允许一个线程执行


synchronized 同步

要做到线程安全,我们可以使用synchronized对方法或者代码块加锁,达到线程同步的效果;

使用synchronized关键字修饰的方法或代码,同一时间内,只允许一个线程执行此代码。

synchronized修饰方法:

    public static synchronized void test(){try {System.out.println("----进入方法----"+Thread.currentThread().getName());Thread.sleep(1000);System.out.println("----执行完毕----"+Thread.currentThread().getName());} catch (InterruptedException e) {throw new RuntimeException(e);}}

修饰代码块:

    //同步代码块public static void testA(){System.out.println("进入方法"+Thread.currentThread().getName());synchronized (SyncThreadB.class){System.out.println("进入同步代码块"+Thread.currentThread().getName());try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("结束同步代码块"+Thread.currentThread().getName());}}

锁对象

在Java中,synchronized关键字用于实现线程同步,保证共享资源的安全访问。当一个线程请求进入synchronized代码块时,它必须先获得锁对象(也称为监视器对象、互斥锁),只有获得锁对象的线程才能进入临界区(synchronized代码块)执行代码。其他线程在未获取到锁对象时会进入等待状态,直到锁对象被释放。

锁对象可以是任意Java对象,可以是共享资源本身,也可以是一个专门用于控制同步访问的对象。当某个线程获得锁对象后,其他线程就无法同时进入相同的synchronized代码块,只能等待锁对象被释放。这样就保证了同一时间只有一个线程能够访问共享资源,从而避免了多线程并发访问带来的数据不一致或竞争条件的问题。

使用synchronized需要指定锁对象:

synchronized修饰成员方法时,锁对象就是 this(当前对象)

修饰静态方法时,锁对象是 类的类对象 如 obj.getClass() 或者 类名.class

类对象:用来描述一个类中定义的内容的对象。


锁的分类

以下是几种常见的锁分类:

  1. 悲观锁和乐观锁:悲观锁认为在并发情况下会发生冲突,所以默认加锁来保护共享资源。乐观锁则认为并发冲突的概率较低,采用无锁或轻量级锁的方式来实现并发控制。悲观锁有锁对象,乐观锁没有锁对象。

  2. 公平锁和非公平锁:公平锁按照线程请求锁的顺序进行获取,保证了先来后到的公平性。非公平锁则允许线程插队,不保证获取锁的顺序,提高了吞吐量。

  3. 可重入锁和不可重入锁:可重入锁允许同一个线程多次获取同一个锁对象的锁。当线程已经持有锁时,再次获取锁时不会被阻塞,而是增加锁的计数。不可重入锁则不允许同一个线程多次获取同一个锁。(可重入锁在同步代码块中遇到相同的锁对象的同步代码块,不需要再获取锁对象的权限,直接进入执行;Java里面全部都是可重入锁)

  4. 偏向锁,轻量级锁(自旋锁)和重量级锁:偏向锁适用于只有一个线程访问同步代码块的情况;轻量级锁适用于多个线程竞争同步代码块的情况,但竞争不激烈的场景;而重量级锁适用于竞争激烈的场景,多个线程频繁竞争同步代码块的情况。

偏向锁是一种针对线程访问同步代码块的优化手段。当一个线程获取了一个同步代码块的锁之后,如果没有其他线程竞争该锁,则持有锁的线程会偏向于该锁,在以后的访问中无需再经过同步操作,提高了性能。

轻量级锁(自旋锁)是一种针对多个线程竞争同步代码块的优化手段。当一个线程尝试获取一个同步代码块的锁时,如果当前锁处于偏向状态且偏向线程是当前线程,则可以直接获取锁而无需进入阻塞状态。如果当前锁不处于偏向状态,或者处于偏向状态但是偏向线程不是当前线程,则需要使用自旋等待锁的释放,而不阻塞线程。

重量级锁是一种针对多个线程竞争同步代码块的一种常规锁机制。当多个线程尝试获取同一个锁时,除了自旋等待锁的释放外,还会将未获取到锁的线程阻塞起来,直到锁的持有者释放锁,被阻塞的线程才能继续执行。


synchronized是什么锁?

synchronized关键字可以被看作是一种悲观锁,使用锁对象来实现线程同步。它确保在同一时间只有一个线程可以获取到锁对象,并进入synchronized代码块执行。其他线程需要等待锁对象被释放后才能进入。

synchronized关键字默认是非公平锁,也就是说,不会按照线程的启动顺序来获取锁,而是随机的。当多个线程同时竞争锁时,并不保证先尝试获取锁的线程一定会获得锁。

synchronized关键字是可重入锁,同一个线程可以重复获取锁对象。在同步代码块中,遇到相同的锁对象的同步代码块,不需要再次获取锁对象的权限,而是直接进入执行。

关于synchronized的锁类型,涉及到锁的状态。当没有竞争时,synchronized使用偏向锁来优化,如果有竞争,升级为轻量级锁(自旋锁),如果自旋不成功,则进一步升级为重量级锁。

综上所述,synchronized关键字可以被看作是一种悲观锁,使用锁对象实现线程同步。它是非公平锁,支持可重入性,并且在不同的竞争情况下可能升级为不同的锁类型。


乐观锁的实现方式?

乐观锁是一种并发控制机制,用于解决多线程同时访问共享资源可能导致的数据不一致问题。乐观锁的实现方式有两种常见的方式:CAS(Compare and Swap)和版本号控制

CAS(比较并交换)是一种无锁并发控制方式,它通过比较共享资源的当前值与期望值是否相等来判断其他线程是否修改了该值。如果相等,则将共享资源的值更新为新值,如果不相等,则表示有其他线程已经修改了该值,此时需要重新读取共享资源的值并重试。CAS操作是原子的,因此可以确保并发安全。

版本号控制是通过为共享资源增加一个版本号来实现的。每次修改共享资源时,都会更新版本号。当一个线程要修改共享资源时,首先读取共享资源的版本号,并保存为当前版本号。如果其他线程在此期间已经修改了共享资源,则当前版本号与保存的版本号不相等,此时需要放弃修改操作。通过版本号的比较,可以确保只有最新的修改才能成功。

两种方式各有优缺点。CAS方式由于没有锁的开销,在低并发情况下性能较好,但在高并发情况下会导致大量的重试,降低效率。版本号控制方式则可以避免重试,但需要维护额外的版本号字段,增加了存储和计算开销。

综上所述,选择使用哪种乐观锁实现方式,需要根据具体的应用场景和性能需求来决定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/50292.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle 性能指标查询

查看表空间大小以及数据文件大小 select dt.TABLESPACE_NAME, concat(dt.MAX_SIZE,(MB)) total, concat(ddf.total_space,(MB)) used from dba_tablespaces dt,(SELECT tablespace_name,sum(bytes) / (1024 * 1024) total_spaceFROM dba_data_fileswhere TABLESPACE_NAME like…

dsp c6657 SYS/BIOS学习笔记

1 SYS/BIOS简介 SYS/BIOS是一种用于TI的DSP平台的嵌入式操作系统&#xff08;RTOS&#xff09;。 2 任务 2.1 任务调度 SYS/BIOS任务线程有0-31个优先级&#xff08;默认0-15&#xff0c;优先级0被空闲线程使用&#xff0c;任务最低优先级为1&#xff0c;最高优先级为15&am…

使用 EJS 模板引擎的示例

使用 EJS 模板引擎的示例 EJS&#xff08;Embedded JavaScript&#xff09;是一种简单的模板引擎&#xff0c;允许你在 HTML 中嵌入 JavaScript 代码。以下是一个使用 EJS 模板引擎的完整示例&#xff0c;包括设置 Express.js 项目、配置 EJS 视图引擎和创建 EJS 模板文件。 …

Java | Leetcode Java题解之第264题丑数II

题目&#xff1a; 题解&#xff1a; class Solution {public int nthUglyNumber(int n) {int[] dp new int[n 1];dp[1] 1;int p2 1, p3 1, p5 1;for (int i 2; i < n; i) {int num2 dp[p2] * 2, num3 dp[p3] * 3, num5 dp[p5] * 5;dp[i] Math.min(Math.min(num2…

2024年网络安全焦点:新兴威胁与防御技术创新

概述 2024年&#xff0c;随着网络技术的发展&#xff0c;网络安全面临的威胁也在不断演变。本文将深入探讨2024年网络安全领域的最新威胁与防御技术创新&#xff0c;并分析它们对企业及个人安全的影响。 新兴威胁分析 云集中风险 随着越来越多的企业将数据和服务迁移至云端…

鸿蒙笔记--存储

这一节了解一下鸿蒙中常用存储API&#xff0c;主要有LocalStorage &#xff0c;AppStorage&#xff0c;PersistentStorage&#xff0c;LocalStorage 是一种页面级UI状态存储机制&#xff0c;主要用于在UIAbility内和页面间共享状态数据。通过使用特定的装饰器&#xff0c;Local…

昇思25天学习打卡营第20天|CV-ResNet50图像分类

打卡 目录 打卡 图像分类 ResNet网络介绍 数据集准备与加载 可视化部分数据集 残差网络构建 Building Block 结构 代码实现 Bottleneck结构 代码实现 构建ResNet50网络 代码定义 模型训练与评估 可视化模型预测 重点&#xff1a;通过网络层数加深&#xff0c;感知…

数据输入输出的概念

文章目录 数据输入输出的概念及在C语言中的实现简单的格式输入与输出用简单的printf函数输出数据用简单的scanf函数输入数据较复杂的输入输出格式控制输出数据格式控制 数据输入输出的概念及在C语言中的实现 数据的输入与输出是相对于计算机而言的。其中&#xff1a; 从计算机…

Linux的shell的date命令

用于生成备份文件的例子 fp"/etc/samba/smb.conf" ; cp -a ${fp} ${fp}.$(date %0y%0m%0d%0H%0M%0S).bak带纳秒ns fp/etc/samba/smb.conf ; cp -a $fp $fp.$(date %0y%0m%0d%0H%0M%0Sns%0N).bakfp/etc/samba/smb.conf ; cp -a $fp $fp.$(date %0y%0m%0d%0…

昇思25天学习打卡营第33天|共赴算力时代

文章目录 一、平台简介二、深度学习模型2.1 处理数据集2.2 模型训练2.3 加载模型 三、共赴算力时代 一、平台简介 昇思大模型平台&#xff0c;就像是AI学习者和开发者的超级基地&#xff0c;这里不仅提供丰富的项目、模型和大模型体验&#xff0c;还有一大堆经典数据集任你挑。…

BM58 字符串的排列

1.题目描述 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围&#xff1a;n<10n<10 要求&#…

本地搭建rtmp拉流

本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 下载地址: 从微信公众号发送关键词 rtmp可获取下载地址 文章目录 本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 拿到之后如图所下&#xff1f;二、配置obs文…

Spark_Oracle_I_通过jdbc读取oracle程序报错invalid character

问题背景&#xff1a; 我原先是通过我么api直接读取的oracle,现在由于要并行读取这个oracle数据库表数据&#xff0c;因此采用jdbc的方式&#xff0c;一开始我把sql变成query直接查&#xff0c;所以报上面的问题。部分样例代码如下 val date "2024/07/01" val quer…

华为网络模拟器eNSP安装部署教程

eNSP是图形化网络仿真平台&#xff0c;该平台通过对真实网络设备的仿真模拟&#xff0c;帮助广大ICT从业者和客户快速熟悉华为数通系列产品&#xff0c;了解并掌握相关产品的操作和配置、提升对企业ICT网络的规划、建设、运维能力&#xff0c;从而帮助企业构建更高效&#xff0…

一个函数统一238个机器学习R包,这也太赞了吧

Caret 是一个试图标准化机器学习过程的一个包。Caret 对 R 中最常用的机器学习方法 (目前支持238个R包)提供了统一的接口。 进行数据预处理 实现机器学习方法流程化模型构建 通过参数组合和交叉验证评估模型的参数 选择最优模型 评估模型性能 一键满足各种掉包&#xff0c…

Linux开启coredump

在Linux系统中&#xff0c;C/C程序崩溃是常见的问题之一。Coredump是指当一个程序崩溃时&#xff0c;系统把程序运行时的内存数据以二进制文件的形式保存下来&#xff0c;以便程序开发者进行崩溃分析。本文将介绍如何开启并配置Coredump 1、查看并配置coredump 在Linux系统中…

JavaScript实战 - 一个能够做圆周运动的模型

一个能够做圆周运动的模型 HTML 文件JavaScript 文件总结 作者&#xff1a;逍遥Sean 简介&#xff1a;一个主修Java的Web网站\游戏服务器后端开发者 主页&#xff1a;https://blog.csdn.net/Ureliable 觉得博主文章不错的话&#xff0c;可以三连支持一下~ 如有需要我的支持&…

分组背包--完全背包

分组背包:多个物品分组&#xff0c;每组只能取1件 每一组的物品都可能性展开就可以&#xff0c;时间复杂度为O(物品的数量*背包的容量) 分组背包 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStre…

基于微信小程序+SpringBoot+Vue的垃圾分类系统(带1w+文档)

基于微信小程序SpringBootVue的垃圾分类系统(带1w文档) 基于微信小程序SpringBootVue的垃圾分类系统(带1w文档) 本垃圾分类小程序也是紧跟科学技术的发展&#xff0c;运用当今一流的软件技术实现软件系统的开发&#xff0c;让环保方面的信息完全通过管理系统实现科学化&#xf…

【Jackson】注解及其使用

Jackson库提供了多种注解&#xff08;annotations&#xff09;&#xff0c;可以用来控制JSON序列化和反序列化的行为。这些注解允许你灵活地映射Java对象与JSON数据之间的关系。下面将详细介绍一些常用的Jackson注解及其用法。 1. JsonProperty 作用: 用于指定JSON属性与Java…