2024年Go最全字节跳动面试题整理(3),阿里P8架构师的Golang大厂面试题总结

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

被volatile修饰的变量在内存中是共享的,在编译器上通过volatile关键字可以禁止指令重排序,在硬件上则是通过内存屏障禁止指令重排序。volatile不会执行加锁操作,因此不会阻塞线程,它是比synchronized关键字更轻量级的同步机制。增加了volatile之后建立了两个线程的happen-before先后顺序。

指令重排序参考链接:指令重排序和内存屏障 - 张小云的博客 - 博客园

happen-before参考链接:面试官为什么总是问happens-before规则,看完这篇文章你就懂了

6、ClassLoader有哪几种,双亲委派机制是为了解决什么问题?如何打破双亲委派机制?

ClassLoader有启动类加载器(BootStrap ClassLoader,加载核心库)、扩展类加载器(Extension ClassLoader,加载jre/lib/ext目录下的扩展jar)、应用类加载器(Application ClassLoader,默认,加载应用程序主函数类)、自定义类加载器(User ClassLoader)。

双亲委派机制就是:如果一个类加载器收到了类加载的请求,这个类加载器不会先尝试加载这个类,而是会先把这个请求委派给自己的父类加载器去完成,在每个层次的类加载器都是依此类推的。比如,在加载一个类时先去判断是否用启动类加载器加载过,若已经加载过则不再加载;再判断是否被扩展类加载器加载过,若已加载则不再加载…

双亲委派机制的优点是:1、保证了JVM提供的核心类不被篡改,保证class执行安全。2、防止重复加载同一个class。

打破双亲委派机制:1、重写loadClass()方法。2、线程上下文加载器。参考链接:【JVM笔记】如何打破双亲委派机制?_小七的博客-CSDN博客_如何打破双亲委派机制

7、spring的三级缓存是什么?为什么要用三级缓存?

spring三级缓存是为了解决对象间的循环依赖问题。在DefaultSingletonBeanRegistry类中定义了三个集合singletonObjects、earlySingletonObjects、singletonFactories,它们就是三级缓存,一级缓存存放已经属性赋值初始化后的单例bean,二级缓存存放已经实例化但还未属性赋值的单例,三级缓存存放单例bean的工厂。

8、spring下的事务传播级别

事务:访问/更新数据库中数据项的最小程序执行单元。

脏读:一个事务访问数据并对数据进行修改,但事务还未提交,另一个事务也在读这个数据,这样会造成脏读。

不可重复读:在同一个事务内,多次读同一个数据。比如第一个事务两次读取同一个数据,但第二个事务的修改导致第一个事务两次读取的数据不一致。

幻读:事务不独立执行时发生。比如第一个事务修改表中的全部数据,第二个事务也修改了表中的数据向其添加一行,然后第一个事务发现表中还有没有修改的数据行。

解决方案:调整事务隔离级别。

TransactionDefinition接口中定义了七个事务传播行为:

  • PROPAGATION_REQUIRED :如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
  • PROPAGATION_SUPPORTS :如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
  • PROPAGATION_MANDATORY :如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
  • PROPAGATION_REQUIRES_NEW :总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
  • PROPAGATION_NOT_SUPPORTED :总是非事务地执行,并挂起任何存在的事务。
  • PROPAGATION_NEVER :总是非事务地执行,如果存在一个活动事务,则抛出异常
  • PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

参考链接:Spring五个事务隔离级别和七个事务传播行为-阿里云开发者社区

Isolation 属性一共支持五种事务设置:

  • DEFAULT —— 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .
  • 未提交读(READ_UNCOMMITTED) —— 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
  • 已提交读(READ_COMMITTED) ——  会出现不可重复读、幻读问题(锁定正在读取的行),Oracle默认隔离级别
  • 可重复读(REPEATABLE_READ) —— 会出幻读(锁定所读取的所有行),Mysql默认隔离级别
  • 可串行化(SERIALIZABLE) —— 保证所有的情况不会发生(锁表)

9、如果一个非事务方法调用了另一个事务方法会怎样?JDK动态代理和CGLIB动态代理区别?

spring同一个类中一个非事务方法调用另一个事务方法(加了@Transactional(rollbackFor = Exception.class))会失效,原因是因为spring的声明式事务使用的是AOP生成了一个代理对象,只有调用那个代理对象的方法,事务才有效。

JDK动态代理和CGLIB动态代理区别,1、JDK针对实现了接口的类生成代理,CGLIB针对指定的类生成代理;2、当Bean实现接口时Spring采用JDK动态代理;当Bean未实现接口时Spring使用CGLIB实现动态代理;3、CGLIB底层采用ASM字节码生成框架,虽然字节码生成效率更高,但是在JDK1.8后对JDK进行了优化,调用次数少时性能优于CGLIB动态代理。

动态代理参考链接:JDK动态代理与CGLib动态代理的区别 - 水木湛清华 - 博客园

10、除了JDK和CGLIB两种AOP方案,还有什么方法可以实现AOP?

还有AspectJ静态编译织入,静态代理的缺点就是我们需要对每一个方法编写我们的代理逻辑,造成了工作的繁琐和复杂,AspectJ解决了这样的问题,在编译class字节码时在方法周围加上业务逻辑,复杂的工作由特定的编译器来做。通过@Aspect+@Before/@After/@AfterRunning/@AfterThrowing/@Around对方法进行前置通知/后置通知/返回通知/异常通知/环绕通知。

参考链接:Java JDK代理、CGLIB、AspectJ代理分析比较_蜗牛的专栏-CSDN博客

11、Redis ZSET的内部实现

Redis对象由redisObject结构体表示,Redis中的每个键值对的键和值都是一个redisObject。如下

typedef struct redisObject {
    unsigned type:4;            // 对象的类型,包括 /* Object types */
    unsigned encoding:4;        // 底部为了节省空间,一种type的数据,可以采用不同的存储方式
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;         // 引用计数
    void *ptr;
} robj;

Redis共有五种类型的对象:字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(SortedSet),其中有序集合也叫ZSET。

/* The actual Redis Object */
#define OBJ_STRING 0
#define OBJ_LIST 1 
#define OBJ_SET 2
#define OBJ_ZSET 3
#define OBJ_HASH 4

ZSET内部实现是通过跳表(Skip List)的数据结构实现,它是基于并联的链表,前提条件是有序集合。可参看前面一篇文章。

12、链表反转实现(递归)

public class ReverseList {
    static class ListNode {
        volatile int val;
        volatile ListNode next;
        ListNode(int x) {
            val = x;
        }
    }

    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        ListNode newHead = reverse(head);
        ListNode cur = newHead;
        while (cur != null){
            System.out.println(cur.val);
            cur = cur.next;
        }
    }

    public static ListNode reverse(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        ListNode temp = head.next;
        ListNode newHead = reverse(head.next);
        temp.next = head;
        head.next = null;
        return newHead;
    }
}

13、https加密过程

HTTPS(全称: Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道。采用对称密钥加密+非对称密钥加密结合的方式保护浏览器和服务端的通信安全。

加密过程:客户端发起握手请求,以明文传输请求信息(版本信息、加密套件候选列表、压缩算法候选列表、随机数、扩展字段等)——> 服务器端向CA认证机构申请证书,并返回协商结果信息给客户端(包括协议版本、加密套件、压缩算法、随机数以及证书) ——> 客户端验证证书合法性,并用证书中的公钥给通信用的对称密钥进行加密,再发送给服务器端 ——> 服务器接收后用私钥解密拿到对称密钥,然后服务器端和客户端可以用对称密钥加密信息通信。

参考链接:HTTPS加密(握手)过程 - 简书

14、输入http到浏览器的流程

输入http协议的网址到浏览器的流程:

  1. 请求后,浏览器首先会解析这个域名,查看本机/etc/hosts文件看有没有与域名对应的规则,如果有则用hosts文件里的ip地址。
  2. 如果hosts文件没有,浏览器会请求到本地DNS(Domain Name System)服务器,如果本地DNS服务没有,则本地DNS向DNS根服务器查询,查到IP后返回给浏览器,并记录缓存记录。
  3. 客户端和服务器端建立TCP连接。
  4. 再进行HTTP请求和HTTP响应报文。
  5. 释放TCP连接。

15、DNS解析的方式有哪些?(递归、迭代)

DNS 查询以各种不同的方式进行解析。客户机有时也可通过使用从以前查询获得的缓存信息就地应答查询。DNS 服务器可使用其自身的资源记录信息缓存来应答查询,也可代表请求客户机来查询或联系其他 DNS 服务器,以完全解析该名称,并随后将应答返回至客户机。这个过程称为递归。
另外,客户机自己也可尝试联系其他的 DNS 服务器来解析名称。如果客户机这么做,它会使用基于服务器应答的独立和附加的查询,该过程称作迭代,即DNS服务器之间的交互查询就是迭代查询。

参考链接:DNS原理及其解析过程 - 极客小乌龟 - 博客园

16、Java实现线程安全的三种方式?

1、同步代码块。2、同步方法。3、Lock锁机制。

17、线程池的七个参数?自定义RejectedExecutionHandler有哪几种实现?

  • corePoolSize 线程池核心线程大小
  • maximumPoolSize 线程池最大线程数量
  • keepAliveTime 空闲线程存活时间
  • unit 空闲线程存活时间单位
  • workQueue 工作队列(①基于数组的有界阻塞队列ArrayBlockingQueue;②基于链表的无界阻塞队列LinkedBlockingQuene;③不缓存任务的阻塞队列SynchronousQuene;④具有优先级的无界阻塞队列PriorityBlockingQueue)
  • threadFactory 线程工厂
  • handler 拒绝策略(①CallerRunsPolicy—除非线程池关闭,否则直接执行被拒绝任务;②AbortPolicy—直接丢弃任务,并抛出RejectedExecutionException异常,默认策略;③DiscardPolicy—直接丢弃任务,什么都不做;④DiscardOldestPolicy—抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列)

自定义RejectedExecutionHandler的实现——实现RejectedExecutionHandler接口,重写​rejectedExecution方法。用法:1、获取线程信息;2、获取线程的上下文信息。

18、网盘项目断点续传的功能是如何实现?

断点续传是由服务器给客户端一个已经上传的位置标记position,然后客户端再将文件指针移动到相应的position,通过输入流将文件剩余部分读出来传输给服务器。

19、进程、线程和协程的区别?进程间通信方式?

  • 进程是任务调度的最小单位,每个进程各自都独立一块内存;(同步)
  • 线程是程序执行流的最小单位,是处理器调度和分派的最小单位;(同步)
  • 协程是一种用户态的轻量级线程,协程拥有自己的寄存器上下文和栈;(异步,保留上一次调用时的状态)

进程间通信方式:

  • 管道:半双工,Go语言和Java在并发处理上多了双向通道channel来在goroutine间传输数据。
  • 消息队列:消息队列允许不同进程以消息队列的形式发送给任意的进程。
  • 共享内存:每个进程都有自己的虚拟内存空间,不同的进程映射到不同的物理内存空间。
  • 信号量:信号量实际上是一个计数器,信号量主要实现进程之间的同步和互斥,而不是存储通信内容。信号量两种操作:p操作为申请资源,会将数值减去M,表示这部分被他使用了,其他进程暂时不能用;v操作是归还资源操作,告知归还了资源可以用这部分。
  • 信号:在操作系统中,不同信号用不同的值表示,每个信号设置相应的函数,一旦进程发送某一个信号给另一个进程,另一进程将执行相应的函数进行处理。
  • 套接字:套接字Socket, Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

20、select和epoll?

select,poll,epoll都是IO多路复用的机制。参考链接:select、poll、epoll之间的区别(搜狗面试) - aspirant - 博客园 - aspirant - 博客园")

21、数据库事务的级别,为什么RR隔离级别下还会出现幻读?

  • DEFAULT —— 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .
  • 未提交读(READ_UNCOMMITTED) —— 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
  • 已提交读(READ_COMMITTED) ——  会出现不可重复读、幻读问题(锁定正在读取的行),Oracle默认隔离级别
  • 可重复读(REPEATABLE_READ) —— 会出幻读(锁定所读取的所有行),Mysql默认隔离级别
  • 可串行化(SERIALIZABLE) —— 保证所有的情况不会发生(锁表)

可重复读隔离级别并没有完全解决幻读问题,如果同一事务里只存在普通的select快照读是不会产生幻读。如果在这个事务里通过当前读或者更新后快照读就会产生幻读。

补充:

普通读(快照读,Consistent Read,undo log + MVCC 实现),执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁。

当前读(锁定读,Locking Read,行记录锁+间隙锁 实现)

参考链接:当前读和快照读的区别_Data & Analysis-CSDN博客_快照读和当前读

MVCC:多版本并发控制,为了提高数据库并发性能,更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。参考链接:https://www.jianshu.com/p/8845ddca3b23

22、JVM内存分区

23、JVM内存溢出有哪几种,什么时候会出现栈内存溢出,如何排查?

  1. 栈溢出(StackOverflowError):方法运行的时候栈的深度超过了虚拟机容许的最大深度所致。出现这种情况,一般情况下是程序错误所致的,比如写了一个死递归,就有可能造成此种情况。对于栈内存溢出,根据《Java 虚拟机规范》中文版:如果线程请求的栈容量超过栈允许的最大容量的话,Java 虚拟机将抛出一个StackOverflow异常;如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将抛出一个OutOfMemory 异常。
  2. 堆溢出(OutOfMemoryError:Java heap space):我们需要根据内存溢出的时候产生的dump文件来具体分析(需要增加-XX:+HeapDumpOnOutOfMemoryErrorjvm启动参数)。出现此种问题的时候有可能是内存泄露,也有可能是内存溢出了。
  3. 持久代溢出(OutOfMemoryError:PermGen spce):Hotspot jvm通过持久带实现了Java虚拟机规范中的方法区,而运行时的常量池就是保存在方法区中的,因此持久带溢出有可能是运行时常量池溢出,也有可能是方法区中保存的class对象没有被及时回收掉或者class信息占用的内存超过了我们配置。
  4. OutOfMemoryError:unable to create native thread:1)程序创建的线程数超过了操作系统的限制。对于Linux系统,我们可以通过ulimit -u来查看此限制。2)给虚拟机分配的内存过大,导致创建线程的时候需要的native内存太少。

参考:[转]JVM内存溢出的几种方式比较 - DarrenChan陈驰 - 博客园

24、linux中如何进行字符串查找?vim中?

cat filename | grep -C 5 ‘关键字’ (显示日志里匹配字串那行以及前后5行)

cat filename | grep -B 5 ‘关键字’ (显示匹配字串及前5行)

cat filename | grep -A 5 ‘关键字’ (显示匹配字串及后5行)

25、文件句柄是什么?

在文件I/O中,要从一个文件读取数据,应用程序首先要调用操作系统函数并传送文件名,并选一个到该文件的路径来打开文件。该函数取回一个顺序号,即文件句柄(file handle),该文件句柄对于打开的文件是唯一的识别依据。要从文件中读取一块数据,应用程序需要调用函数ReadFile,并将文件句柄在内存中的地址和要拷贝的字节数传送给操作系统。当完成任务后,再通过调用系统函数来关闭该文件。一个句柄就是一个文件、设备、套接字(socket)或管道的一个名字。

26、淘宝的数据库设计?

27、高并发如何优化?

高并发常见的优化办法:

  • 硬件升级
  • 负载均衡
  • 服务器集群
  • 数据库读写分离——主库增删改(INSERT、DELETE、UPDATE)操作,从库SELECT查询操作。
  • 数据库分库分表——垂直切分(垂直分库、垂直分表);水平切分(库内分表、分库分表)。参考链接:数据库分库分表,何时分?怎样分?详细解读,一篇就够了_azhuyangjun的博客-CSDN博客_数据库分库分表
  • 表建立相应的索引
  • 页面静态化——静态资源(html、图片、css样式、文本、js等),避免重复请求这些资源,减少http请求,例如CDN。参考链接:页面静态化_yinbucheng的博客-CSDN博客_页面静态化
  • 缓存技术(MemCache、Redis)
  • 禁止外部盗链——别人盗用你的链接转发流量,解决方法:1、判断引用地址(Request.UrlReferrer属性);2、使用登陆验证;3、使用Cookies;4、使用Post下载;5、使用图形验证码;6、使用动态文件名;7、打包下载
  • 控制大文件下载——大文件下载会占用很大流量,耗费CPU资源,使得网站相应能力下降

28、一致性哈希原理?

29、缓存击穿、缓存穿透、缓存雪崩区别?

  • 缓存击穿:缓存中没有的数据在数据库中,但由于访问量过多导致数据库瞬间压力增大。解决方案:缓存中设置热点数据永不过期。
  • 缓存穿透:缓存和数据库中都没有的数据,但用户不断发起请求从而导致数据库压力过大。解决方案:用户鉴权校验。
  • 缓存雪崩:缓存中大批量数据过期,压力全到了数据库服务器引起宕机。解决方案:过期时间设置随机,防止大批量数据同一时间过期;热点数据永不过期。

30、TCP四次挥手细节?

31、delete、drop、truncate区别?

执行速度上drop > truncate >> delete;

delete为数据操作语言(DML,Data Manipulation Language)删除记录,同时将删除操作作为事务记录在redo log(记录事务操作的物理日志)和undo log(保存数据操作之前版本,用于回滚),其他,binlog是主从复制中用主库的binlog进行重播达到主从同步。

truncate和drop是数据定义语言(DDL,Data Definition Language),drop是删除数据库表,立刻释放磁盘空间无法找回;truncate是快速清空一个表并重置auto_increment的值,delete不会。

32、同步辅助类CountDownLatch CyclicBarrier Semaphore区别?

  • CountDownLatch类:通过继承了AbstractQueuedSynchronizer的同步器的计数值来控制。countDown方法计数值减一,await方法会获取共享锁进入等待状态直到计数值减为0。
  • Semaphore类:实现最多指定数量的线程并发访问,超过count数的线程需要等到count数个线程中有线程执行完毕且释放资源才可以。线程执行调用acquire方法,释放调用release方法。
  • CyclicBarrier类:它没有像前面两个类使用AQS而是用了ReentrantLock。使指定数量的线程等待直到线程到齐,然后一起执行下一步。可循环执行,当等到指定数量的线程调用await方法。

33、Redis持久化机制RDB和AOF区别?

RDB(Redis DataBase):把数据以快照的形式保存在磁盘上(二进制文件dump.rdb)。触发方式:save(新替旧)、besave(默认,fork子进程保存)、自动化(配置)。缺点:全量备份。

AOF(Append Only File):redis会将每一个收到的写命令都通过write函数追加到文件(日志记录)中,fork新进程来重写。触发方式:always(每次修改同步)、everysec(异步,每秒记录)、no(从不同步)。缺点:日志文件比RDB快照文件大,恢复慢。

参考链接:详解Redis中两种持久化机制RDB和AOF(面试常问,工作常用)

34、bean的作用域?

  • 单例(singleton):它是默认的选项,在整个应用中,Spring只为其生成一个Bean的实例。
  • 原型(prototype):当每次注入,或者通过Spring IoC容器获取Bean时,Spring都会为它创建一个新的实例。
  • 会话(session):在Web应用中使用,就是在会话过程中Spring只创建一个实例。
  • 请求(request):在Web应用中使用的,就是在一次请求中Spring会创建一个实例,但是不同的请求会创建不同的实例。

35、bean的声明周期?

36、bean的初始化?

初始化执行顺序:构造方法->Before Initialization->使用PostConstruct注解->InitializingBean接口->init-method指定的初始化方法->After Initialization

37、Java8新特性有哪些?

  • lambda表达式:函数作为参数传递进方法中,使代码简洁。
  • 方法引用:使用一对冒号“::”,eg:ArrayList.forEach(System.out::println)
  • 函数式接口:如Runnable、Callable、Comparator、FileFilter等。eg:Predicate接口,相当于通过predicate传递的参数表达式过滤出对应的数据。
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for(Integer n: list) {
            //test方法评估参数表达式,返回布尔类型
            if(predicate.test(n)) {
                System.out.println(n + " ");
            }
        }
}
  • 默认方法:方法名前加default关键字。解决接口的修改与现有的实现不兼容的问题。
  • Stream(流):以一种声明的方式处理数据。流的来源可以是是集合,数组,I/O channel,产生器generator等,流的聚合操作有如filter, map, reduce, find,match, sorted。
public static void main(String[] args) {
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
    List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
}
  • Optional类:Optional 是个容器,它可以保存类型T的值,或者仅仅保存null,这样我们就不用显式进行空值检测。Optional 类的引入很好的解决空指针异常。

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

string.isEmpty()).collect(Collectors.toList());
}


* Optional类:Optional 是个容器,它可以保存类型T的值,或者仅仅保存null,这样我们就不用显式进行空值检测。Optional 类的引入很好的解决空指针异常。



[外链图片转存中...(img-TQEOlJ4W-1715374662634)]
[外链图片转存中...(img-sonZ4n6O-1715374662635)]
[外链图片转存中...(img-n8DD5Uvx-1715374662635)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值