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

JVM快速入门(1)JVM体系结构、运行时数据区、类加载器、线程共享和独享、分区、Java对象实例化

5.1 JVM体系结构

在这里插入图片描述

  • 线程独占区-程序计数器(Program Counter Register)

    • 程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器;
    • 在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成;
    • 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
  • 线程独占区-Java虚拟机栈(Java Virtual machine Stacks)

    • Java虚拟机栈与线程生命周期相同。其描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程。

    • 局部变量表存放了编译器可知的各种基本数据类型(boolen,byte,char,short,int,float,long,double),对象引用(reference类型)和returnAddress类型(指向了一条字节码指令的地址)。

    • 在这个区域中,Java虚拟机规范规定了两种异常情况:

    • 如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverFlowError异常;
    • 如果虚拟机栈可以动态扩展(当前大部分Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),并且扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
  • 线程独占区-本地方法栈(Native Method Stack)

    • 本地方法栈与虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,本地方法栈为虚拟机使用到的Native方法服务。
    • 由于虚拟机规范中没有对本地方法栈中的语言、使用方式与数据结构进行强制规定,有的虚拟机(入Sun HotSpot虚拟机)直接把本地方法栈和虚拟机栈合二为一。
    • 本地方法栈会抛出StackOverflowError异常和OutOfMemoryError异常。
  • 线程共享区-Java堆(Java Heap)

    • Java堆是Java虚拟机所管理的内存中最大的一块,在虚拟机启动时创建,其唯一目的就是存放对象实例:所有的对象实例以及数组都要在堆上分配(但随着JIT编译器的发展与逃逸分析技术逐渐成熟,所有的对象分配在堆上也渐渐不是那么绝对了)。
    • Java堆是垃圾收集器管理的主要区域,现在收集器基本采用分代收集算法,所以Java堆还可细分为:新生代和老年代;再细致点分为Eden空间(伊甸园区),From Survivor空间(幸存区0),To Survivor空间(幸存区1)等;
    • 根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续即可;
    • 如果堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
  • 线程共享区-方法区(Method Area)

    • 方法区用于存储已被虚拟机加载的类信息(构造方法、接口定义)、常量、静态变量、即时编译器编译后的代码(运行时常量池)等数据
    • 所谓的方法区为永久代的说法,仅仅是因为HotSpot虚拟机将GC分代收集扩展至方法区,或者说使用永久代来实现方法而已。对于其他虚拟机是不存在永久代的说法的。
    • 运行时常量池是方法区的一部分,用于存放编译器生成的各种字面量和符号引用,一般还会存放翻译出来的直接引用。这部分内容将在类加载后进入方法区的运行时常量池中存放。当常量池无法再申请到内存时抛出OutOfMemoryError异常。
  • 举例:

            String str1 = "abd";String str2 = new String("abd");System.out.println(str1 == str2);System.out.println(str1 == str2.intern());输出:falsetrue分析:(1) String str1 = "abc" ,str1指向常量池;(2) String str2 = new String("abc");str2指向堆内存对象,二者地址不同所以str1 == str2 结果为false;(3) 但是str2.intern()会把字符串值从堆内存移动到常量池中(如果常量池存在则返回该值的地址),这样一来str2和str1都是指向常量池的abc。  如下图所示:     
    

    在这里插入图片描述

5.2 JVM详细架构图

在这里插入图片描述

5.3 JVM架构之运行时数据区

  • 线程共享区包括:堆、元空间
  • 线程私有区包括:虚拟机栈、本地方法栈、程序计数器

运行时数据区

包括:程序计数器(PC寄存器)、Java虚拟机栈、Java堆、方法区、运行时常量池、本地方法栈等等。

5.3.1 PC 寄存器,也叫程序计数器
  • 1、JVM支持多个线程同时运行,每个线程拥有一个程序计数器,是线程私有的,用来存储指向下一条指令的地址。
  • 2、在创建线程的时候,创建相应的程序计数器。
  • 3、执行本地native方法时,程序计数器的值为undefined。
  • 4、是一块比较小的内存空间,是唯一一个在JVM规范中没有规定OutOfMemoryError的内存区域。
5.3.2 虚拟机栈
  • 栈是由一系列帧(Frame)组成(因此Java栈也叫作帧栈),是线程私有的。
  • 帧是用来保存一个方法的局部变量、操作数栈(java没有寄存器,所有的参数传递使用操作数栈)、常量池指针、动态链接、方法返回值等。
  • 每一次方法调用创建一个帧并压栈,退出方法的时候,修改栈顶指针就可以把栈帧中的内容销毁。
  • 局部变量表存放了编译期可知的各种基本数据类型和引用数据类型、每个slot存放32位的数据,long、double占两个槽位。
  • 栈的优点:存取速度比堆快,仅次于程序计数器。
  • 栈的缺点:存在栈中的数据太小,生存期是在编译期决定的,缺乏灵活性。
  • StackOverflowError异常:当线程请求的栈深度大于虚拟机所允许的深度;
  • OutOfMemoryError异常:如果栈的扩展时无法申请到足够的内存。
5.3.3 Java堆
  • 用来存放应用系统创建的对象和数组,所有线程共享Java堆。
  • GC主要管理堆空间,对分代GC来说,堆也是分代的。
  • 堆的优点:运行期动态分配内存大小,自动进行垃圾回收。
  • 堆的缺点:效率相对较慢。
5.3.4 方法区的理解
  • 对于HotSpotJVM而言,方法区还有一个别名,叫做Non-Heap(非堆),目的就是和堆区分开,所以方法区看做是一块独立于Java堆的内存空间。
  • 方法区(Method Area)和Java堆一样,是各个线程共享的内存区域;
  • 方法区在JVM启动时被创建,并且它的实际的物理内存空间和Java堆区一样,都是可以不连续的;
  • 方法区的大小,和堆空间一样,可以选择固定大小或者可扩展;
  • 方法区的大小,决定了系统可以保持多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutOfMemoryError:Metaspace;
  • 关闭JVM就是释放这个区域的内存。

HotSpot中方法区的演进:

  • JDK1.6及之前,有永久代,静态变量存放在永久代上,常量池在方法区了;
  • JDK1.7,有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中;
  • JDK1.8及之后,无永久代,类型信息、字段、方法、常量保存在本地内存的元空间。但字符串常量池、静态变量仍在堆上。
  • 永久代、元空间二者并不只是名字改变了,内部结构也调整了。
5.3.5 运行时常量池:
  • 运行时常量池是方法区的一部分;

  • 常量池是Class文件的一部分,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中;

  • 在加载类和接口到JVM中,就会创建对应的运行时常量池;

  • JVM为每个已加载的类型(类或接口)都维护一个常量池,池中的数据项像数组一样,通过索引访问的;

  • 运行时常量池中包含各种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能获得的方法或字段引用。此时不再是常量池中的符合地址了,这里换为真实地址:

  • 运行时常量池,相对于Class文件常量池的另一重要特征是:具备动态性;
  • String.intern()
  • 党创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则JVM就会抛出OOM异常。
5.3.6 本地方法栈
  • 在JVM中用来支持native方法执行的栈就是本地方法栈。
  • 在JVM规范中,并没有对本地方发展的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

在这里插入图片描述

5.4 类加载器

  • 作用:加载class文件

  • 加载器:

    • 1.虚拟机自带的加载器
    • 2.启动类(根)加载器(Bootstrap classLoader):主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和AppClassLoader。
    • 3.扩展类加载器(ExtClassLoader):主要负责加载jre/lib/ext目录下的一些扩展的jat.
    • 4.应用程序加载器(AppClassLoader):主要负责加载应用程序的主函数类。
  • 图示:

    在这里插入图片描述

  • 双亲委派机制

    • (1)类加载器收到类加载的请求;

    • (2)将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器(根加载器);

    • (3)启动加载器检查是否能够加载当前这个类,能加载就结束,使用当前的加载器;否则,抛出异常,通知子加载器进行加载;

    • (4)重复步骤3

    ​ Class Not Found

    null: java 调用不到 c/c++写的调用不到

5.5 Java对象的实例化过程

java世界里面对象无处不在,在创建对象的时候主要经过哪些步骤?

5.5.1 对象的创建过程

类加载检查–>分配内存–>初始化零值–>设置对象头–>执行init方法

如图:

在这里插入图片描述

1.类加载检查
   虚拟机遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用并且检查这个符号引用代表的类是否被加载,解析,初始化过,如果没有,那必须执行相应的类加载过程

new 的指令对应到语言层面上讲: new关键词,对象克隆,对象序列化等

2.分配内存
在类加载检查通过后,接下来虚拟机将为新生对象分配内存,对象所需内存的大小在类加载完成后便可完成确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来
3.初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值()不包括对象头

4.设置对象头(分不同的操作系统,如32位的,64位的)

初始化零值之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等这些信息,这些信息存放在对象的对象头Object Header之中 在HotSpot虚拟机中,对象在内存中的储存布局可以分为3块区域: 对象头(Header),实例数据(Instance Data)和对齐填充(Padding)

HotSpot虚拟机的对象头包括两部分信息:第一部分: 储存对象本的运行时数据,如哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等第二部分: 类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例

如下是32 位的对象头

在这里插入图片描述

5.执行init()方法

对象按照程序员的意愿进行初始化;对应到语言层面来讲,就是属性赋值(注意:这是程序员自己赋的值)和执行构造方法

5.5.2 从Java源码到编译class到加载整体过程

对象创建的过程,主要经过如下5步:

  1. 判断类有没有被加载

  2. 如果没有被加载过(才开始加载类(就是类的加载过程))

  3. 初始化 :就是给一些变量进行初始化。

  4. 设置对象头(比较难理解)。

  5. 执行方法: 对对象进行赋值,和执行构造方法。

这里再从源码.java文件到编译的.class文件到加载,详细描述第2步中的类的加载过程:

加载.class文件的时候 window系统下调用底层的应该jvm.dll文件创建java虚拟机去创建一个引导类加载器(C++实现的) 此时java虚拟机已经创建 此时会调用java实现的类加载器启动 加载loadClass方法加载真正的磁盘文件上面的字节码文件,再去发起调用main()方法,此时程序就启动了

类加载到使用整个过程有如下几步: 加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载

1、加载:

​ 在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用 类的main()方法,new对象等等

2、验证:

​ 校验字节码文件的正确性

3、准备:

​ 给类的静态变量分配内存,并赋予默认值 比如Boolean类型默认 false 这些默认值是java虚拟机自己规定的,如果是加final修饰直接就会变成常量 直接赋值了

4、解析:

​ 将符号引用替换为直接引用,就是会将该阶段会把一些静态方法(符号引用,比如 main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链 接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接 引用,下节课会讲到动态链接(在类加载的时候可能不会加载 只有程序运行到这里才会去加载)

5、初始化:

对类的静态变量初始化为指定的值,执行静态代码块

在这里插入图片描述

相关文章:

JVM快速入门(1)JVM体系结构、运行时数据区、类加载器、线程共享和独享、分区、Java对象实例化

5.1 JVM体系结构 线程独占区-程序计数器(Program Counter Register) 程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器;在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数…...

CSS3新属性(学习笔记)

一、. 圆角 border-radius:; 可以取1-4个值&#xff08;规则同margin&#xff09; 可以取px和% 一般用像素&#xff0c;画圆的时候用百分比&#xff1a;border-radius:50%; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…...

41-Vue-webpack基础

webpack基础 前言什么是webpackwebpack的基本使用指定webpack的entry和output 前言 本篇开始来学习下webpack的使用 什么是webpack webpack: 是前端项目工程化的具体解决方案。 主要功能&#xff1a;它提供了友好的前端模块化开发支持&#xff0c;以及代码压缩混淆、处理浏览…...

数据仓库的分层理论

数据仓库的分层理论是为了更好地组织和管理数据&#xff0c;支持复杂的数据分析和决策支持。在这一理论中&#xff0c;数据仓库被分为多个层次&#xff0c;每个层次都有其特定的作用和设计原则。以下是每一层的详细介绍&#xff0c;以及以销售人员为例的Doris建表实例。 ODS层…...

MySQL 8.0-索引- 不可见索引(invisible indexes)

概述 MySQL 8.0引入了不可见索引(invisible index)&#xff0c;这个在实际工作用还是用的到的&#xff0c;我觉得可以了解下。 在介绍不可见索引之前&#xff0c;我先来看下invisible index是个什么或者定义。 我们依然使用拆开来看&#xff0c;然后再把拆出来的词放到MySQL…...

Uibot6.0 (RPA财务机器人师资培训第3天 )财务招聘信息抓取机器人案例实战

训练网站&#xff1a;泓江科技 (lessonplan.cn)https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981(本博…...

Eureka和Nacos的关系

目录 它们的比较&#xff1a; 结论&#xff1a; Eureka和Nacos都是服务发现和注册中心&#xff0c;它们在微服务架构中扮演着关键角色&#xff0c;但它们是由不同的组织开发的&#xff0c;服务于类似但不完全相同的目的。以下是它们之间的关系&#xff1a; Eureka&#xff1a…...

极简自建web视频会议,私有云,rtmp/rtsp/webrtc一键参会直播会议互动方案

随着视频互动深入工作日常&#xff0c;很多客户需要自建一个会议&#xff0c;监控的交互平台&#xff0c;目前外面不管是开源还是非开源的平台&#xff0c;都是极为复杂&#xff0c;一般linux安装库关联部署复杂&#xff0c;非技术人员根本没办法使用&#xff0c;不方便集成部署…...

5G智能网关助力工业铸造设备监测升级

随着物联网技术的迅猛发展和工业4.0浪潮的推进&#xff0c;传统工业正面临着严峻的转型升级压力。在这一背景下&#xff0c;铸造行业——这一典型的传统重工业领域&#xff0c;也必须积极探索借助5G、物联网、边缘计算等技术提升生产经营效率的新路径。 本文就基于佰马合作伙伴…...

奇舞周刊第523期:来自 rust 生态的强烈冲击?谈谈 Leptos 在语法设计上的精妙之处...

奇舞推荐 ■ ■ ■ 来自 rust 生态的强烈冲击&#xff1f;谈谈 Leptos 在语法设计上的精妙之处 过去很长一段时间&#xff0c;前端框架们都在往响应式的方向发展。同时又由于 React hooks 的深远影响&#xff0c;函数式 响应式成为了不少前端心中最理想的前端框架模样。Solid …...

《边缘计算:连接未来的智慧之桥》

随着物联网、5G等技术的快速发展&#xff0c;边缘计算作为一种新兴的计算模式&#xff0c;正逐渐引起人们的广泛关注。边缘计算通过将数据处理和存储功能放置在距离数据产生源头更近的位置&#xff0c;实现了更快速、更可靠的数据处理和交换&#xff0c;为各行各业带来了前所未…...

php 各种魔术函数的触发条件

2024.3.20 1、__construct() __construct() 用于在创建对象时自动触发 当使用 new 关键字实例化一个类时&#xff0c;会自动调用该类的 __construct() 方法 <?php class MyClass {public function __construct() {echo "已触发 __construct 一次";} }$obj new …...

Linux的学习之路:2、基础指令(1)

一、ls指令 上篇文章已经说了一点点的ls指令&#xff0c;不过那还是不够的&#xff0c;这篇文章会介绍更多的指令&#xff0c;最起码能使用命令行进行一些简单的操作&#xff0c;下面开始介绍了 ls常用选项 -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含文件。 -d…...

0103设计算法-算法基础-算法导论第三版

文章目录 一、分治法二、分析分治算法结语 我们可以选择使用的算法设计技术有很多。插入排序使用了增量方法&#xff1a;在排序子数组 A [ 1 ⋯ j − 1 ] A[1\cdots j-1] A[1⋯j−1]后&#xff0c;将单个元素 A [ j ] A[j] A[j]插入子数组的适当位置&#xff0c;产生排序好的子…...

[NCTF2019]SQLi ---不会编程的崽

欸嘿&#xff0c;继续sql注入。又是新的sql注入类型 很直接哦&#xff0c;给出了sql查询语句。简单扫描一下&#xff0c;robots.txt还能访问。里边提示hint.txt $black_list "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00…...

上位机开发 halcon坐标转轴坐标

背景 上位机开发中有一种相机叫标定相机,主要是有来给某些要进行根据CAD图点位计算时当前产品实际点位坐标时使用的一种标定测量相机。主要原理是根据两个或多个指定的标定点进行取图计算圆心坐标,再将视觉计算出的圆心坐标和取图时的轴坐标进行偏差计算。最后得到标定点轴的…...

[数据结构]二叉树(下)

一、二叉树的节点和深度关系 1.满二叉树 我们可以假设二叉树有N个节点&#xff0c;深度为h我们可以恒容易得到满二叉树每行的节点数&#xff0c;然后错位相减,算出节点与高度的关系。 2.完全二叉树 注意我这个是因为最后一行的节点数为1。 二、向上调整建堆和向下调整建堆的时…...

动手学深度学习|notebook教程

D2L.AI&#xff5c;《动手学深度学习》Notebooks 目录 面向中文读者的能运行、可讨论的深度学习教科书 含 PyTorch、NumPy/MXNet、TensorFlow 和 PaddlePaddle 实现 被全球 70 多个国家 500 多所大学用于教学 github 下面是整理好的&#xff0c;可以直接运行的notebook 0 前…...

C#面:简述 .NET Framework 类库中的“命名空间”

在 C# 中&#xff0c;命名空间&#xff08;Namespace&#xff09;是一种用于组织和管理代码的机制。它提供了一种将相关的类、接口、结构体和其他类型组织在一起的方式&#xff0c;以便更好地管理和维护代码。 .NET Framework类库中的命名空间是一种逻辑上的分组&#xff0c;它…...

android.os.TransactionTooLargeException解决方案,Kotlin

android.os.TransactionTooLargeException解决方案&#xff0c;Kotlin 首先&#xff0c;特意制造一个让Android发生TransactionTooLargeException的场景&#xff0c;一个Activity启动另外一个Activity&#xff0c;在Intent的Bundle里面塞入一个大的ArrayList: import android.…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版

1.题目描述 2.思路 当前的元素可以重复使用。 &#xff08;1&#xff09;确定回溯算法函数的参数和返回值&#xff08;一般是void类型&#xff09; &#xff08;2&#xff09;因为是用递归实现的&#xff0c;所以我们要确定终止条件 &#xff08;3&#xff09;单层搜索逻辑 二…...