字节跳动正式启动2021届秋季校招!这份字节跳动历年校招Android面试真题解析,你确定不收藏?(下)

*   线程共享数据区包含:
    *   Java堆:用于存放几乎所有的对象实例和数组;是垃圾收集器管理的主要区域,也被称做“GC堆”;是Java虚拟机所管理的内存中最大的一块
    *   方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是**常量池(Constant Pool Table)**,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放
  • 引申:谈谈JVM的堆和栈差别

Q:谈谈垃圾回收机制?为什么引用计数器判定对象是否回收不可行?知道哪些垃圾回收算法?

  • 技术点:垃圾回收机制
  • 思路:从如何判定对象可回收、如果回收具体算法这两方面展开谈垃圾回收机制,详见要点提炼| 理解JVM之GC
  • 参考回答:
  • (1)判定对象可回收有两种方法:
    • 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。然而在主流的Java虚拟机里未选用引用计数算法来管理内存,主要原因是它难以解决对象之间相互循环引用的问题,所以出现了另一种对象存活判定算法。
    • 可达性分析法:通过一系列被称为『GC Roots』的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。其中可作为GC Roots的对象:虚拟机栈中引用的对象,主要是指栈帧中的本地变量、本地方法栈中Native方法引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象
  • (2)回收算法有以下四种:
    • 分代收集算法:是当前商业虚拟机都采用的一种算法,根据对象存活周期的不同,将Java堆划分为新生代和老年代,并根据各个年代的特点采用最适当的收集算法。
      • 新生代:大批对象死去,只有少量存活。使用『复制算法』,只需复制少量存活对象即可。
        • 复制算法:把可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用尽后,把还存活着的对象『复制』到另外一块上面,再将这一块内存空间一次清理掉。
      • 老年代:对象存活率高。使用『标记—清理算法』或者『标记—整理算法』,只需标记较少的回收对象即可。
        • 标记-清除算法:首先『标记』出所有需要回收的对象,然后统一『清除』所有被标记的对象。
        • 标记-整理算法:首先『标记』出所有需要回收的对象,然后进行『整理』,使得存活的对象都向一端移动,最后直接清理掉端边界以外的内存。
  • 引申:谈谈每种回收算法的优缺点

Q:Java中引用有几种类型?在Android中常用于什么情景?

  • 技术点:Java引用类型
  • 思路:分条解释每种类型的特点和适用场景,详见要点提炼| 理解JVM之GC
  • 参考回答:引用的四种类型
    • 强引用(StrongReference):具有强引用的对象不会被GC;即便内存空间不足,JVM宁愿抛出OutOfMemoryError使程序异常终止,也不会随意回收具有强引用的对象。
    • 软引用(SoftReference):只具有软引用的对象,会在内存空间不足的时候被GC;软引用常用来实现内存敏感的高速缓存
    • 弱引用(WeakReference):只被弱引用关联的对象,无论当前内存是否足够都会被GC;强度比软引用更弱,常用于描述非必需对象;常用于解决内存泄漏的问题
    • 虚引用(PhantomReference):仅持有虚引用的对象,在任何时候都可能被GC;常用于跟踪对象被GC回收的活动;必须和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

Q:类加载的全过程是怎样的?什么是双亲委派模型?

  • 技术点:类加载机制、双亲委派模型
  • 思路:类加载机制的含义以及每个阶段的作用,在解释双亲委派模型之前需要先理解类加载器,详见要点提炼| 理解JVM之类加载机制
  • 参考回答:
  • (1)类加载机制:是虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验转换解析初始化,最终形成可被虚拟机直接使用的Java类型的过程。另外,类型的加载、连接和初始化过程都是在程序运行期完成的,从而通过牺牲一些性能开销来换取Java程序的高度灵活性。下面介绍类加载每个阶段的任务:
    • 加载(Loading):通过类的全限定名来获取定义此类的二进制字节流;将该二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构,该数据存储数据结构由虚拟机实现自行定义;在内存中生成一个代表这个类的java.lang.Class对象,它将作为程序访问方法区中的这些类型数据的外部接口
    • 验证(Verification):确保Class文件的字节流中包含的信息符合当前虚拟机的要求,包括文件格式验证、元数据验证、字节码验证和符号引用验证
    • 准备(Preparation):为类变量分配内存,因为这里的变量是由方法区分配内存的,所以仅包括类变量而不包括实例变量,后者将会在对象实例化时随着对象一起分配在Java堆中;设置类变量初始值,通常情况下零值
    • 解析(Resolution):虚拟机将常量池内的符号引用替换为直接引用的过程
    • 初始化(Initialization):是类加载过程的最后一步,会开始真正执行类中定义的Java字节码。而之前的类加载过程中,除了在『加载』阶段用户应用程序可通过自定义类加载器参与之外,其余阶段均由虚拟机主导和控制
  • (2)类加载器:不仅用于加载类,还和这个类本身一起作为在JVM中的唯一标识。常见类加载器类型有:
    • 启动类加载器:是虚拟机自身的一部分
    • 扩展类加载器、应用程序类加载器、自定义类加载器:独立于虚拟机外部
  • (3)双亲委派模型:表示类加载器之间的层次关系。
    • 前提:除了顶层启动类加载器外,其余类加载器都应当有自己的父类加载器,且它们之间关系一般不会以继承(Inheritance)关系来实现,而是通过组合(Composition)关系来复用父加载器的代码。
    • 工作过程:若一个类加载器收到了类加载的请求,它先会把这个请求委派给父类加载器,并向上传递,最终请求都传送到顶层的启动类加载器中。只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

Q:工作内存和主内存的关系?在Java内存模型有哪些可以保证并发过程的原子性、可见性和有序性的措施?

  • 技术点:JVM内存模型、线程安全
  • 思路:理解Java内存模型的结构、详见要点提炼| 理解JVM之内存模型&线程
  • 参考回答:Java内存模型就是通过定义程序中各个变量访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。
    • 模型结构如图:

其中 ,主内存(Main Memory)是所有变量的存储位置,每条线程还有自己的工作内存,用于保存被该线程使用到的变量的主内存副本拷贝。为了获取更好的运行速度,虚拟机可能会让工作内存优先存储于寄存器和高速缓存中。

  • 保证并发过程的原子性、可见性和有序性的措施:
    • 原子性(Atomicity):一个操作要么都执行要么都不执行。
      • 可直接保证的原子性变量操作有:readloadassignusestorewrite,因此可认为基本数据类型的访问读写是具备原子性的。
      • 若需要保证更大范围的原子性,可通过更高层次的字节码指令monitorentermonitorexit来隐式地使用lockunlock这两个操作,反映到Java代码中就是同步代码块synchronized关键字。
    • 可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。
      • 通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现。
      • 提供三个关键字保证可见性:volatile能保证新值能立即同步到主内存,且每次使用前立即从主内存刷新;synchronized对一个变量执行unlock操作之前可以先把此变量同步回主内存中;被final修饰的字段在构造器中一旦初始化完成且构造器没有把this的引用传递出去,就可以在其他线程中就能看见final字段的值。
    *   **有序性**(Ordering):程序代码按照指令顺序执行。
        *   如果在本线程内观察,所有的操作都是有序的,指“线程内表现为串行的语义”;如果在一个线程中观察另一个线程,所有的操作都是无序的,指“指令重排序”现象和“工作内存与主内存同步延迟”现象。
        *   提供两个关键字保证有序性:`volatile` 本身就包含了禁止指令重排序的语义;`synchronized`保证一个变量在同一个时刻只允许一条线程对其进行lock操作,使得持有同一个锁的两个同步块只能串行地进入。
    

Q:JVM、Dalvik、ART的区别?

  • 技术点:虚拟机对比
  • 思路:分别谈谈JVM和Dalvik、Dalvik和ART的区别,详见Jvm、Dalvik和Art的区别
  • 参考回答:
    • Dalvik :是Google公司自己设计用于Android平台的Java虚拟机,不是Java虚拟机,没有遵循Java虚拟机规范,具体区别如下图:

  • ART:代替Dalvik,应用无需每次运行都要先编译,而是在安装时就预编译字节码到机器语言,提升运行时效率;预先编译也使得ART占用空间比Dalvik大,即用空间换时间;由于减少运行时重复编译,可明显改善电池续航,降低了能耗。

Q:Java中堆和栈的区别?

  • 技术点:内存管理
  • 思路:从存放数据和内存回收角度出发
  • 参考回答: 在java中,堆和栈都是内存中存放数据的地方,具题区别是:
    • 栈内存:主要用来存放基本数据类型局部变量;当在代码块定义一个变量时会在栈中为这个变量分配内存空间,当超过变量的作用域后这块空间就会被自动释放掉。
    • 堆内存:用来存放运行时创建的对象,比如通过new关键字创建出来的对象和数组;需要由Java虚拟机的自动垃圾回收器来管理。

1.5 操作系统

Q:操作系统中进程和线程的区别?

  • 技术点:进程、线程
  • 参考回答:
    • 进程是操作系统分配和管理资源的单位,线程是CPU调度和管理的单位,是CPU调度的最小单元
    • 进程拥有独立的地址空间,而线程间共享地址空间
    • 进程创建的开销比较大,线程创建的开销小
  • 引申:可谈谈安卓系统中对进程和线程的理解

Q:进程死锁的产生和避免?

  • 技术点:死锁
  • 思路:可从死锁含义、产生条件、解决办法、避免手段出发
  • 参考回答:死锁是指多个进程因循环等待资源而造成无法执行的现象,它会造成进程无法执行,同时会造成系统资源的极大浪费。
    • 死锁产生的条件:
      • 互斥使用:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
      • 不可抢占:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
      • 请求和保持:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
      • 循环等待:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
    • 解决死锁的策略:
      • 银行家算法:判断此次请求是否造成死锁若会造成死锁,否则拒绝该请求
      • 鸵鸟算法:忽略该问题,常用于在极少发生死锁的的情况
    • 死锁的避免:通过合理的资源分配算法来确保永远不会形成环形等待的封闭进程链,即“如果一个进程的当前请求的资源会导致死锁,系统拒绝启动该进程;如果一个资源的分配会导致下一步的死锁,系统就拒绝本次的分配”

1.6 数据结构&算法

Q:怎么理解数据结构?
Q:什么是斐波那契数列?
Q:迭代和递归的特点,并比较优缺点
Q:了解哪些查找算法,时间复杂度都是多少?
Q:了解哪些排序算法,并比较一下,以及适用场景
Q:快排的基本思路是什么?最差的时间复杂度是多少?如何优化?
Q:AVL树插入或删除一个节点的过程是怎样的?
Q:什么是红黑树?
Q:100盏灯问题
Q:老鼠和毒药问题,加个条件,必须要求第二天出结果
Q:海量数据问题
Q:(手写算法)二分查找
Q:(手写算法)反转链表
Q:(手写算法)用两个栈实现队列
Q:(手写算法)多线程轮流打印问题
Q:(手写算法)如何判断一个链有环/两条链交叉
Q:(手写算法)快速从一组无序数中找到第k大的数/前k个大的数
Q:(手写算法)最长(不)重复子串

  • 技术点:数据结构、手写算法
  • 思路:篇幅问题,该部分将单独做一篇总结

1.7 设计模式

Q:谈谈MVC、MVP和MVVM,好在哪里,不好在哪里?

  • 技术点:MVC、MVP、MVVM
  • 思路:详见MVP、MVVM模式
  • 参考回答:
    • MVP的含义:
      • Model:数据层,负责存储、检索、操纵数据。
      • View:UI层,显示数据,并向Presenter报告用户行为。
      • Presenter:作为View与Model交互的中间纽带,从Model拿数据,应用到UI层,管理UI的状态,响应用户的行为。
    • MVP相比于MVC的优势
      • 分离了视图逻辑和业务逻辑,降低了耦合。
      • Activity只处理生命周期的任务,代码变得更加简洁
      • 视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性。
      • Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
      • 把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM。
    • MVVM的含义:与MVP类似,利用数据绑定(Data Binding)、依赖属性(Dependency Property)、命令(Command)、路由事件(Routed Event)等新特性,打造了一个更加灵活高效的架构。
    • MVVM相比于MVP的优势:在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI,获取用户的输入和操作也需要通过UI控件的引用,但在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多。

Q:如何理解生产者消费者模型?

  • 技术点:生产者消费者模型
  • 参考回答:生产者消费者模型通过一个缓存队列,既解决了生产者和消费者之间强耦合的问题,又平衡了生产者和消费者的处理能力。
    • 具体规则:生产者只在缓存区未满时进行生产,缓存区满时生产者进程被阻塞;消费者只在缓存区非空时进行消费,缓存区为空时消费者进程被阻塞;当消费者发现缓存区为空时会通知生产者生产;当生产者发现缓存区满时会通知消费者消费。
    • 实现关键:synchronized保证对象只能被一个线程占用;wait()让当前线程进入等待状态,并释放它所持有的锁;notify()&notifyAll()唤醒一个(所有)正处于等待状态的线程

Q:是否能从Android中举几个例子说说用到了什么设计模式?

  • 技术点:设计模式
  • 参考回答:
    • View事件分发:责任链模式
    • BitmapFactory加载图片:工厂模式
    • Adapter:适配器模式
    • Builder:建造者模式
    • Adapter.notifyDataSetChanged():观察者模式
    • Binder机制:代理模式

Q:装饰模式和代理模式有哪些区别?

  • 技术点:装饰模式、代理模式
  • 参考回答:
    • 使用目的不同:代理模式是给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用;装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能
    • 构造不同:代理模式内部保持对目标对象的引用;装饰模式是通过构造函数传参的方式得到目标对象

Q:实现单例模式有几种方法?懒汉式中双层锁的目的是什么?两次判空的目的又是什么?

  • 技术点:单例模式
  • 参考回答:实现单例模式常见的两种方式:
    (1)懒汉式:延迟加载,同时也要保证多线程环境下会产生多个single对象(DCL)

public class Singleton {

private Singleton() {}
private volatile static Singleton instance;//第一层锁:保证变量可见性

public static Singleton getInstance() {
if (single == null) {//第一次判空:无需每次都加锁,提高性能
synchronized (Singleton.class) {//第二层锁:保证线程同步
if (single == null) {//第二次判空:避免多线程同时执行getInstance()产生多个single对象
single = new Singleton();
}
}
}
return single;
}
}

(2)饿汉式:在类加载初始化时就创建好一个静态的对象供外部使用

public class Singleton {

private Singleton() {}
private static Singleton single = new Singleton();

public static Singleton getInstance() {
return single;
}
}

Q:谈谈了解的设计模式原则?

  • 技术点:设计模式原则
  • 参考回答:
    • 单一职责原则:一个类只负责一个功能领域中的相应职责
    • 开放封闭原则:对扩展开放,对修改关闭
    • 依赖倒置原则:抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程
    • 迪米特法则:应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用
    • 合成/聚合复用原则:要尽量使用合成/聚合,尽量不要使用继承

1.8 数据库

Q:数据库中的事务了解吗?事务的四大特性?

  • 技术点:事务
  • 参考回答:
    • 事务是并发控制的单位,是用户定义的一个操作序列。它指这些操作要么都做,要么都不做,以便服务器保持数据的完整性。
    • 事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
    • 事务的四大特性(ACID特性):原子性(Atomicity)表示事务中包括的诸操作要么全做,要么全不做;一致性(Consistency)表示事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态;隔离性(Isolation)表示一个事务的执行不能被其他事务干扰;持续性(Durability)表示一个事务一旦提交,它对数据库中数据的改变就应该是永久性的
  • 引申:谈谈数据库事务的并发控制

Q:如何理解数据库的范式?

  • 技术点:范式
  • 思路:详见实例讲解数据库的3大范式和5大约束
  • 参考回答:
    • 第一范式(1NF):数据表中的每个字段必须是不可拆分的最小单元,即确保每一列的原子性
    • 第二范式(2NF):满足1NF后,要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系
    • 第三范式(3NF):必须先满足第二范式,要求表中的每一列只与主键直接相关而不是间接相关,即表中的每一列只能依赖于主键

1.9 hr问题

Q:请简单的自我介绍一下

  • 可能意图:开场白;短期内快速了解候选人情况;考察表达能力和逻辑思维;是否有备而来;第一印象
  • 思路:说亮点、语言精炼、熟练回答

Q:谈谈项目经历,为什么会做,怎么做的,遇到的难点?
Q:谈谈实习经历,做了什么,收获有哪些?
Q:谈谈学习Android的经历,有哪些学习方法和技巧?
Q:成绩怎么样?奖学金情况?
Q:学过哪些课程?那门课印象最深刻/最有意义/学的最好/最不喜欢?为什么?
Q:学习生活中遇到什么挫折,如何解决的?
Q:家是哪里的?是独生子女吗?从小的家庭环境如何?
Q:平常有哪些兴趣爱好?大学参加了哪些校园活动?
Q:评价一下自己的优缺点?/用x个词形容你自己。/别人都是怎样评价你的?
Q:觉得自己博客写的最好的文章是什么?为什么?
Q:觉得自己的优势是什么?

  • 可能意图:了解候选人的性格、各方面特质,是否符合企业价值观;了解其沟通表达能力、学习能力等才能,是否具有可塑性
  • 思路:结合具体实例体现自己确是企业想要的人才

Q:是否会考研?/为何不保研?
Q:近x年的职业规划?
Q:为什么想来我们公司?/为何不转正留在xx?
Q:对公司/部门是否有了解?
Q:为何会选择做技术?/对女生做开发的看法?
Q:还投过那些公司,进展如何?如果xx和xx都给你发offer会如何选择?
Q:有男/女朋友吗?未来有什么规划?
Q:如何看待加班?
Q:意向工作城市是哪?/是否会考虑在xx发展?
Q:对于薪酬有什么想法?

  • 可能意图:了解候选人对企业的意向度和忠诚度,是否值得给发offer
  • 思路:表现出想去该公司的态度、并已为之做了准备

Q:有什么问题想要问我?

  • 可能意图:结束语;主动权交由候选人
  • 思路:咨询和岗位&部门&公司发展相关的情况、探讨对某技术的看法、询问面试官对你的评价、寻求学习等方面的建议、了解后续面试流程和进度;注意,避免问薪资和加班问题、也不要直接说“没有问题”

1.10 项目相关、实习相关技术问题(略)

Q:使用那些版本控制工具?Git和SVN的区别?

  • 技术点:版本控制工具
  • 参考回答:Git和SVN的区别有以下几点:
    • Git是分布式的,而SVN是集中式的(核心区别)
    • Git按元数据方式存储内容,而SVN按文件存储内容
    • 在Git上每个工作成员可以任意在自己的本地版本库开启无限个分支且互不影响,而对于SVN分支是一个完整的目录且这个目录拥有完整的实际文件
    • Git没有一个全局的版本号,而SVN有
    • Git 的内容完整性要优于SVN
    • 在Git中的绝大多数操作都只需要访问本地文件和资源,不必联网就可以看到所有的历史版本记录,而SVN 却需要联网
  • 引申:谈谈两种版本控制工具的优缺点:SVN与GIT的优缺点对比

Q:了解Git工具吗?用过哪些命令?解决冲突时git merge和git rebase的区别?

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
Android进阶视频+面试资料部分截图

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

4lCoPEF.jpg" />

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
[外链图片转存中…(img-ky8AUv9h-1711955529428)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值