hello初窥源码

QT 创建经典的Hello Word程序 QT 创建经典的Hello Word程序,一步步创建QT程序。 阅读详情

目录

hashmap底层原理

B+树底层原理

两种查询方式

ConcurrentHashMap

hashtable

hashtable插入数据

ConcurrentHashMap

多线程

说一下你对线程池的理解

常用的线程池有哪些?

线程池原理知道吗?以及核心参数

sleep()和wait() 有什么区别?

notify()和notifyAll()有什么区别?

Java中synchronized 和 ReentrantLock 有什么不同?

锁优化机制


hashmap底层原理

1、map.put(k,v)实现原理
(1)首先将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
2、map.get(k)实现原理
(1)先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
(2)通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。

  • 红黑树查询:其访问性能近似于折半查找,时间复杂度 O(logn);
  • 链表查询:这种情况下,需要遍历全部元素才行,时间复杂度 O(n);

B+树底层原理

B+树是B树的一种变体,有着比B树更高的查询性能,都是为磁盘等外存储设备设计的一种平衡查找树.

系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,page(页)是其磁盘管理的最小单位(InnoDB存储引擎中默认每个页的大小为16KB).

定义一条记录为一个二元组[key, data]

B树每个节点中不仅包含数据的key值,还有data值。

而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。B+Tree的高度一般都在2~4层

两种查询方式

根节点指针指向叶子节点,叶子节点(即数据节点)之间是一种链式环结构,因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

聚簇索引和非聚簇索引

聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续
聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序。
非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序。
索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。
 

ConcurrentHashMap

hashtable

Hashtable所有的方法都是同步的,因此,它是线程安全的。

Hashtable是通过“拉链法”实现的散列表,因此,它使用数组+链表的方式来存储实际的元素

hashtable插入数据

当向Hashtable中插入数据的时候,首先通过键的hashCode和Entry数组的长度来计算这个值应该存放在数组中的位置index。如果index对应的位置没有存放值,则直接存放到数组的index位置即可,当index有冲突的时候,则采用“拉链法”来解决冲突。

Hashtable通过使用synchronized修饰方法的方式来实现多线程同步,因此,Hashtable的同步会锁住整个数组。在高并发的情况下,性能会非常差,Java5中引入了ConcurrentHashMap

ConcurrentHashMap

ConcurrentHashMap采用了更细粒度的锁来提高在并发情况下的效率。

它由Segment数组结构和HashEntry数组结构组成,Segment数组在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键-值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构;一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素;每个Segment守护着一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

ConcurrentHashMap将Hash表默认分为16个桶,大部分操作都没有用到锁,而对应的put、remove等操作也只需要锁住当前线程需要用到的桶,而不需要锁住整个数据

在大并发的情况下,同时可以有16个线程来访问数据,大大提高了并发性.

多线程

说一下你对线程池的理解

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降
低系统的稳定性,使用线程池可以进行统一的分配,调优和监控

常用的线程池有哪些?

1 newSingleThreadExecutor :创建一个单线程的线程池,此线程池保证所有任务的执行顺序按照任务的提交顺序执行。 newFixedThreadPool:创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线 程达到线程池的最大大小。
2 newCachedThreadPool:创建一个可缓存的线程池,此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM )能够创建的最大线程大小。
3 newScheduledThreadPool:创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。
4 newSingleThreadExecutor :创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

线程池原理知道吗?以及核心参数

首先线程池有几个核心的参数概念:
1. 最大线程数 maximumPoolSize
2. 核心线程数 corePoolSize
3. 活跃时间 keepAliveTime
4. 阻塞队列 workQueue
5. 拒绝策略 RejectedExecutionHandler
当提交一个新任务到线程池时,具体的执行流程如下:
1. 当我们提交任务,线程池会根据 corePoolSize 大小创建若干任务数量线程执行任务
2. 当任务的数量超过 corePoolSize 数量,后续的任务将会进入阻塞队列阻塞排队
3. 当阻塞队列也满了之后,那么将会继续创建 (maximumPoolSize-corePoolSize)个数量的线程来
执行任务,如果任务处理完成, maximumPoolSize-corePoolSize额外创建的线程等待keepAliveTime之后被自动销毁
4. 如果达到 maximumPoolSize ,阻塞队列还是满的状态,那么将根据不同的拒绝策略对应处理

sleep()和wait() 有什么区别?

对于 sleep() 方法,我们首先要知道该方法是属于 Thread 类中的。而 wait() 方法,则是属于 Object 类
中的。
sleep() 方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然保持
者,当指定的时间到了又会自动恢复运行状态。在调用 sleep() 方法的过程中,线程不会释放对象
锁。
当调用 wait() 方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用
notify() 方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。

notify()和notifyAll()有什么区别?

notify 可能会导致死锁,而 notifyAll 则不会 任何时候只有一个线程可以获得锁,也就是说只有一
个线程可以运行 synchronized 中的代码使用notifyall, 可以唤醒 所有处于 wait 状态的线程,使其重新进入锁的争夺队列中,而 notify 只能唤醒一个。
wait() 应配合 while 循环使用,不应使用 if ,务必在 wait() 调用前后都检查条件,如果不满足,必须调
用 notify() 唤醒另外的线程来处理,自己继续 wait() 直至条件满足再往下执行。 notify()是对 notifyAll() 的一个优化,但它有很精确的应用场景,并且要求正确使用。不然可能导致死锁。正确的场景应该是 WaitSet 中等待的是相同的条件,唤醒任一个都能正确处理接下来的事项,如果唤醒的线程无法正确处理,务必确保继续notify() 下一个线程,并且自身需要重新回到 WaitSet中
.

Java中synchronized 和 ReentrantLock 有什么不同?

相似点:
这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如
果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的
区别:
这两种方式最大区别就是对于 Synchronized 来说,它是 java 语言的关键字,是原生语法层面的互
斥,需要 jvm 实现。而 ReentrantLock 它是 JDK 1.5 之后提供的 API 层面的互斥锁,需要 lock() 和 unlock()方法配合 try/fifinally 语句块来完成。
Synchronized进过编译,会在同步块的前后分别形成 monitorenter 和 monitorexit 这个两个字节码指令。在执行monitorenter 指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1 ,相应的,在执行 monitorexit 指令时会将锁计算器就减1 ,当计算器为 0 时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另
一个线程释放为止。 由于ReentrantLock 是 java.util.concurrent 包下提供的一套互斥锁,相比Synchronized , ReentrantLock类提供了一些高级功能,主要有以下3 项:
1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于
Synchronized 来说可以避免出现死锁的情况。
2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized 锁非公平
锁, ReentrantLock 默认的构造函数是创建的非公平锁,可以通过参数 true 设为公平锁,但公平锁
表现的性能不是很好。
3.锁绑定多个条件,一个ReentrantLock 对象可以同时绑定多个对象

锁优化机制

从 JDK1.6 版本之后, synchronized 本身也在不断优化锁的机制,有些情况下他并不会是一个很重量 级的锁了。优化机制包括自适应锁、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁。 锁的状态从低到高依次为无锁 - > 偏向锁 - > 轻量级锁 - > 重量级锁 ,升级的过程就是从低到高,降级在一定条件也是有可能发生的。
自旋锁 :由于大部分时候,锁被占用的时间很短,共享变量的锁定时间也很短,所有没有必要挂起
线程,用户态和内核态的来回上下文切换严重影响性能。自旋的概念就是让线程执行一个忙循环,
可以理解为就是啥也不干,防止从用户态转入内核态,自旋锁可以通过设置-XX:+UseSpining来开
启,自旋的默认次数是 10 次,可以使用-XX:PreBlockSpin设置。
自适应锁 :自适应锁就是自适应的自旋锁,自旋的时间不是固定时间,而是由前一次在同一个锁上
的自旋时间和锁的持有者状态来决定。
锁消除 :锁消除指的是 JVM 检测到一些同步的代码块,完全不存在数据竞争的场景,也就是不需要加锁,就会进行锁消除。
锁粗化 :锁粗化指的是有很多操作都是对同一个对象进行加锁,就会把锁的同步范围扩展到整个操
作序列之外。
偏向锁 :当线程访问同步块获取锁时,会在对象头和栈帧中的锁记录里存储偏向锁的线程 ID ,之后 这个线程再次进入同步块时都不需要CAS 来加锁和解锁了,偏向锁会永远偏向第一
个获得锁的线程,如果后续没有其他线程获得过这个锁,持有锁的线程就永远不需要进行同步,反之,当有其他线程竞争偏向锁时,持有偏向锁的线程就会释放偏向锁。可以用过设置-XX:+UseBiasedLocking开启偏向锁。
轻量级锁 : JVM 的对象的对象头中包含有一些锁的标志位,代码进入同步块的时候,JVM 将会使用
CAS 方式来尝试获取锁,如果更新成功则会把对象头中的状态位标记为轻量级锁,如果更新失败, 当前线程就尝试自旋来获得锁。 整个锁升级的过程非常复杂,我尽力去除一些无用的环节,简单来描述整个升级的机制。 简单点说,偏向锁就是通过对象头的偏向线程ID 来对比,甚至都不需要 CAS 了,而轻量级锁主要就 是通过CAS 修改对象头锁记录和自旋来实现,重量级锁则是除了拥有锁的线程其他全部阻塞。
产生死锁的四个必要条件?
1. 互斥条件:一个资源每次只能被一个线程使用
2. 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放
3. 不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺
4. 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系
从零开始学习PX4源码7(hello world) 本节主要记录如何在PX4中创建一个应用程序hello world 的过程,具体可以参考官网hello sky的过程hello sky。 阅读详情

相关推荐

Hello-world:持续增长

Hello-world keep growing but how?playing game? watch more, think hard 两种获取知识的途径:1、看学习资料,死磕文字;2、积极主动跟人聊天,带有一定目的性的问询。 后者效率高,毕竟 听君一席话,胜读十年书。 没有任何一个工作是十全十美的,每个行业里面的人都在想方设法的逃离自己所在的行业,却不知道自己的地狱已经是他人眼里的天堂。行业没有好坏之分,重要的是找的适合自己的才是最好的! 不要纠结工资,想想五年后能做到什么程度,提升不可替代性。 如果想快速成功,就在一个方向上多坚持一会儿 任何时候都不要放弃提升自己的机会,不要着急享受能力配不上的东西。 R基础及可视化: NGS基础知识: 英语翻译,详见[] CATTI 国家笔译证书 100句工作邮件用语: I am writing to confirm/enquire/inf

ConcurrentHashmap 锁

是一种高效的并发集合,通过分段锁或细粒度锁机制保证了线程安全。它通过合理的锁设计和无锁操作(如 CAS),在高并发环境下提供了优秀的性能。在选择分段数量时,需要平衡内存开销和并发性能。分段并不是越多越好,合理配置并发级别和初始容量,才能充分发挥的性能优势。Java 8 之后的实现通过进一步细化锁的粒度,使得在处理大量并发读写操作时,性能更加优越,适用于大多数并发场景。

Flying_Fish_roe的博客 1782

远程调用之RESTful最佳实践

本文讲述了什么是REST远程调用,已经在开发时如何做到符合REST规范的调用接口

厉害了!把 HashMap 剖析的只剩渣了!

点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 8:55 更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2020 超神之路,很肝~中...

芋艿V 198

RestTemplete远程调用

RestTemplete远程调用技术,升级版的httpclient,对httpclient进行了get post等方法进行了封装,提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。我的代码中包含了get post 的多种访问方式,可以直接拿过来改一下当工具类用,如果需要头信息还要加上头信息等,如有问题请@我。

Verilog中generate for循环的5个实战技巧(附完整代码示例)

本文详细介绍了Verilog中generate for循环的5个高级实战技巧,包括参数化模块实例化、条件化生成、多维硬件结构实现等,并附有完整代码示例。这些技巧能显著提升FPGA开发效率,特别适合中级Verilog开发者学习应用。

weixin_28725949的博客 187

从零开始的ConcurrentHashMap

从0开始手搓ConcurrentHashMap,不含树化操作

weixin_62004364的博客 1288

SVA学习笔记(1)——property基本语法及巧用define与property

巧用define与property,让代码更加灵活

craftsman2018ship的博客 1574

HashMap知识点总结

HashMap、ConcurrentHashMap、线程安全问题

倩mys的博客 1114

Anthropic发布10款金融AI智能体模板深度解析:重构华尔街工作范式

摘要:2026年5月,Anthropic发布10款金融AI智能体模板,标志着AI从辅助工具升级为"虚拟同事"。这些智能体深度集成到Word、Excel等办公软件中,覆盖投行、商行、资管三大场景的核心工作流,预计可提升效率35-85%。技术架构基于Claude3.5Sonnet模型,具备200K上下文窗口和95%+的财务图表解析准确率,并与彭博等金融数据源直连。发布引发传统金融数据服务商股价下跌,摩根大通等机构则视其为成本优化工具。落地需分四阶段推进,关键在于数据治理和复合型人才培养。未来

yyq916的博客 635

瑞萨 RL78 开发环境实战:从 CS+ for CC 到 e² studio 高效开发

本文详细介绍了瑞萨RL78单片机开发环境的选择与配置,对比分析了CS+ for CC和e² studio的特点及适用场景。内容涵盖环境安装、工程创建、调试技巧、外设驱动开发和低功耗设计等实战经验,为开发者提供全面的RL78入门指南,帮助快速上手并高效开发。

4k5l6j7h8的博客 242

Java7 ConcurrentHashMap详解

Java7 ConcurrentHashMapConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些。整个 ConcurrentHashMap 由一个个 Segment 组成,Segment 代表”部分“或”一段“的意思,所以很多地方都会将其描述为分段锁。注意,行文中,我很多地方用了“槽”来代表一个 segment。简单理解就是,Concurr

好好学java 1232

人工蜂鸟算法(AHA)详解:原理、实现与应用

人工蜂鸟算法(AHA)是一种受蜂鸟飞行技能和觅食策略启发的新型元启发式优化算法。该算法模拟蜂鸟的全向飞行、记忆能力和觅食行为,通过引导觅食、领地觅食和迁徙觅食三种策略在解空间高效搜索。AHA将优化问题解类比为食物源,蜂鸟作为搜索代理,利用访问表记录访问信息。算法核心包括三种飞行技能建模(全向、对角线和轴向飞行)以及对应的数学公式实现。Python实现展示了种群初始化、适应度计算和觅食行为模拟等关键步骤。AHA以其高效的全局搜索能力、良好收敛性和鲁棒性,在复杂优化问题中表现优异。

qq_42212808的博客 907

初窥Sentinel集群流控:从源码分析到效果测试

Sentinel从1.4.0 开始引入了集群流控模块,用于控制应用集群内某个 API 的总 QPS 。 在Sentinel集群流控中,主要有两种身份:Token Client和Token Server,实现集群流控的流程就是应用实例(Token Client)向Token Server请求令牌,TokenServer根据集群流控规则来控制总体的QPS。 待解决的问题: 1. 通过Nacos流控规则配置不直观 2. SentinelCluster无官方高可用方案

未完成的空间 5467

基于YOLOv8的包装商品智能检测系统完整指南—含论文、代码

《基于YOLOv8的包装商品智能检测系统》摘要: 本文提出了一套完整的零售商品自动检测解决方案,利用YOLOv8深度学习框架实现高精度、高效率的商品识别。系统针对SKU110K大规模商品数据集(含11,762张高密度货架图像)进行优化,包含数据预处理、模型训练、推理检测和可视化界面全流程。详细介绍了从CSV标注到YOLO格式的转换方法、环境配置指南及技术架构设计。该系统可应用于智能零售、物流仓储等多个场景,有效解决人工盘点效率低、误差大的痛点。实验表明,该系统具备毫秒级检测速度和批量处理能力,为商业数字化转

FJN110的博客 209

【项目实战】自动化测试软件VectorCAST介绍

VectorCAST是一款先进的自动化测试软件。VectorCAST是一款功能强大、易于使用的自动化测试软件。VectorCAST适用于各种嵌入式系统的测试。VectorCAST为嵌入式系统的测试提供了一种高效、可靠的解决方案。VectorCAST提供了一整套完整的测试工具,包括测试管理、代码覆盖、缺陷定位、报告生成等,以帮助开发人员提高测试效率,确保软件质量。VectorCAST支持。

奶爸的编程之路,也就一周冷个三天 2012

openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读

openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读

xuer_07的专栏 2275

鸿蒙接入微信支付 微信H5网页在鸿蒙系统的适配方法(含支付兼容方案) 微信H5适配鸿蒙系统 | ArkWeb识别 | 鸿蒙浏览器UA | 微信支付鸿蒙适配 | 鸿蒙微信判断方式

微信H5网页鸿蒙系统适配指南 针对微信H5网页在鸿蒙系统出现的兼容问题,本文提供完整适配方案。关键点包括: 环境识别:

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1300

LED数码管动态滚动显示“Hello(HELLO)”

C51单片机数码管动态滚动显示“Hello(HELLO)”

初尘屿风的博客 8430

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

在MTK源码中添加hello驱动

在alps/kernel/drivers/char 目录下添加: 1、hello.c

zlcchina的专栏 1243

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

linux 源码安装与第一个驱动hello

一边工作一边时不时的玩下linux ,因为想看下android驱动开发,大家都说android的驱动开发是在linux的驱动开发上封闭了一层,得先知道一些关于linux驱动的知识 新装一个linux系统,我安装的是ubuntu 16.04,本来想装ubuntu 18的这个版本图型界面直观,网络下载太慢了先用着想着搞崩了再装新的。 安装内核源码: 安装头文件:sudo apt-get ins...

魔侠的博客 622

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

初窥c++11:lambda函数及其用法

初窥c++11:lambda函数及其用法 标签: c++11lambda 2014-05-25 19:13 8745人阅读 评论(0) 收藏 举报  分类: C++王者归来(15)  版权声明:本文为博主原创文章,未经博主允许不得转载。 为什么需要lambda函数 匿名函数是许多编程语言都支持的概念,有函数体,没有函数名。195

jfkidear的专栏 351

Linux内核编程入门实例--Hello world 源码和操作流程

Linux内核编程入门实例--Hello world 源码和操作流程 1.打开终端,建立一个文件夹并进入: 2.编写hello.c: vim hello.c #include<linux/kernel.h> #include<linux/init.h> #include<linux/module.h> MODULE_LICENSE("...

Kunaly 755

Linux生成系统树,Linux内核源码树建立加载hello模块

Linux内核源码树建立加载hello模块在加载模块之前,书中说要先建立内核源码树,那么,如何建立内核源码树呢?首先,要先知道你的OS的内核版本,用uname -r可以查得到在/url/src/目录下可以看到对应的版本目录如果没有可以用apt-cache search linux-source获取内核用sudo apt-get install linux-source-3.13.0下载内核下载完成...

weixin_28829339的博客 188

程序人生-Hello’s P2P

计算机系统 大作业 题目程序人生-Hello’s P2P 专业未来技术(人工智能) 学  号7203610830 班  级2036015 学生王一鸣    指导教师史先俊   计算机科学与技术学院 2022年5月 摘要 本文对hello程序的生命周期...

qq_26210695的博客 2522
上一篇: 总结面试题
下一篇: 电商项目介绍
HelloWouldH
博客等级 码龄5年 696粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值