专栏名称: 沉默王二
技术文通俗易懂,吹水文风趣幽默。学 Java,认准二哥的网站 javabetter.cn
目录
相关文章推荐
云南市场监管  ·  一次性筷子都是用二氧化硫漂白的?!还能用吗? ·  13 小时前  
软件小妹  ·  又可白嫖了,安卓和iOS均可使用! ·  昨天  
软件小妹  ·  又可白嫖了,安卓和iOS均可使用! ·  昨天  
湖北商务  ·  正式开放!阿里巴巴落子武汉 ·  2 天前  
湖北商务  ·  正式开放!阿里巴巴落子武汉 ·  2 天前  
风动幡动还是心动  ·  不多说了,赶紧上车 ·  2 天前  
风动幡动还是心动  ·  不多说了,赶紧上车 ·  2 天前  
国家林业和草原局  ·  新闻联播:我国古树名木保护取得积极进展 ·  3 天前  
国家林业和草原局  ·  新闻联播:我国古树名木保护取得积极进展 ·  3 天前  
51好读  ›  专栏  ›  沉默王二

OPPO 开奖 SP了,非常心动。

沉默王二  · 公众号  · 科技自媒体  · 2024-10-16 14:04

主要观点总结

文章主要描述了作者的成功经历,包括其面试经历、技术背景以及加入OPPO的感想。同时介绍了Java相关的知识,包括集合框架、HashMap、泛型、线程生命周期、JVM内存模型、栈溢出、垃圾回收等,以及MySQL事务、索引、Redis的数据结构和持久化方案等。

关键观点总结

关键观点1: 作者的成功经历和技术背景

作者通过不断努力学习和提升自己的技术,成功获得了OPPO的SP offer。作者具有深厚的Java技术功底,对Java的集合框架、HashMap、泛型等有深入的理解。

关键观点2: Java相关知识介绍

文章详细介绍了Java的集合框架、HashMap的工作原理和存在的问题、泛型的用途、线程的生命周期、JVM的内存模型、栈溢出的原因和场景、垃圾回收的过程等。

关键观点3: MySQL和Redis的相关知识

文章介绍了MySQL的事务、索引的原理和失效情况,以及Redis的数据结构和持久化方案,包括哨兵机制和Cluster的工作原理。

关键观点4: 作者的决心和加入OPPO的感想

作者表达了加入OPPO的决心和期待,并分享了编程学习资源和环境,鼓励读者不断学习提升自己。


正文

大家好,我是“卧龙”的第十八代孙诸葛二。

身高约一米八,在一众程序员中,显得格外醒目。虽然常年与代码为伴,但我并非那种格子衫、拘泥于键盘的书生摸样。五官轮廓分明,自带一股英气,尤其是那双目光坚毅的眼睛,可以洞穿所有问题的本质。

常怀家国大义,胸有壮志。

昨日,收到 OPPO 公司的 SP  offer,月 base 24k,互联网服务部门,再加上 1.2K 的房补,让我很是心动。

截图来自二哥的 Java 面试指南专栏

心中默念:此番能夺得“OPPO”城中高位,多赖于座上宾“三分恶”撰写的那份举世闻名的八股秘籍——面渣逆袭。

念在 OPPO 如此有诚意的薪资待遇上,我日后定当为其鞠躬尽瘁,驰骋沙场,图霸业大成。

为后世着想,特把上月我与 OPPO 大将“上官老王”的技术一面纪录于《 Java 面试指南 》中。上官老王,精通“Java、Spring Cloud”之术,号称 OPPO 技艺翘楚。此番得其赏识,实乃荣幸之至。

OPPO 面经同学1一面

介绍Java的集合框架

Java 集合框架可以分为两条大的支线:

①、Collection,主要由 List、Set、Queue 组成:

  • List 代表有序、可重复的集合,典型代表就是封装了动态数组的 ArrayList 和封装了链表的 LinkedList;
  • Set 代表无序、不可重复的集合,典型代表就是 HashSet 和 TreeSet;
  • Queue 代表队列,典型代表就是双端队列 ArrayDeque,以及优先级队列 PriorityQueue。

②、Map,代表键值对的集合,典型代表就是 HashMap。

二哥的 Java 进阶之路:Java集合主要关系

为什么HashMap不是线程安全的?

HashMap 不是线程安全的,主要有以下几个问题:

①、多线程下扩容会死循环。JDK1.7 中的 HashMap 使用的是头插法插入元素,在多线程的环境下,扩容的时候就有可能导致出现环形链表,造成死循环。

二哥的 Java 进阶之路

不过,JDK 8 时已经修复了这个问题,扩容时会保持链表原来的顺序。

②、多线程的 put 可能会导致元素的丢失。因为计算出来的位置可能会被其他线程的 put 覆盖。本来哈希冲突是应该用链表的,但多线程时由于没有加锁,相同位置的元素可能就被干掉了。

二哥的 Java 进阶之路

③、put 和 get 并发时,可能导致 get 为 null。线程 1 执行 put 时,因为元素个数超出阈值而导致出现扩容,线程 2 此时执行 get,就有可能出现这个问题。

二哥的 Java 进阶之路:源码截图

因为线程 1 执行完 table = newTab 之后,线程 2 中的 table 此时也发生了变化,此时去 get 的时候当然会 get 到 null 了,因为元素还没有转移。

和ConcurrentHashMap的差异

HashMap 不是线程安全的,因此在早期的 JDK 版本中,是用 Hashtable 来保证线程安全的。Hashtable 是直接在方法上加 synchronized 关键字,比较粗暴。

因此在 Java 的后期版本中,更推荐使用 ConcurrentHashMap和 Collections.synchronizedMap(Map) 包装器。

ConcurrentHashMap是通过锁机制来实现线程安全的吗?

在 JDK 7 时采用的是分段锁机制(Segment Locking),整个 Map 被分为若干段,每个段都可以独立地加锁。因此,不同的线程可以同时操作不同的段,从而实现并发访问。

初念初恋:JDK 7 ConcurrentHashMap

在 JDK 8 及以上版本中,ConcurrentHashMap 的实现进行了优化,不再使用分段锁,而是使用了一种更加精细化的锁——桶锁,以及 CAS 无锁算法。每个桶(Node 数组的每个元素)都可以独立地加锁,从而实现更高级别的并发访问。

初念初恋:JDK 8 ConcurrentHashMap

对于读操作,通常不需要加锁,可以直接读取,ConcurrentHashMap 内部使用了 volatile 变量来保证内存可见性。

对于写操作,ConcurrentHashMap 使用 CAS 操作来实现无锁的更新,这是一种乐观锁的实现,因为它假设没有冲突发生,在实际更新数据时才检查是否有其他线程在尝试修改数据,如果有,采用悲观的锁策略,如 synchronized 代码块来保证数据的一致性。

泛型的作用是什么?

泛型主要用于提高代码的类型安全,它允许在定义类、接口和方法时使用类型参数,这样可以在编译时检查类型一致性,避免不必要的类型转换和类型错误。

没有泛型的时候,像 List 这样的集合类存储的是 Object 类型,导致从集合中读取数据时,必须进行强制类型转换,否则会引发 ClassCastException。

List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0);  // 必须强制类型转换

Java里线程的生命周期

也就是说,线程的生命周期可以分为五个主要阶段:新建、可运行、运行中、阻塞/等待、和终止。线程在运行过程中会根据状态的变化在这些阶段之间切换。:

三分恶面渣逆袭:Java线程状态变化

说一下JVM内存模型

按照 Java 的虚拟机规范,可以细分为 程序计数器 虚拟机栈 本地方法栈 方法区 等。

三分恶面渣逆袭:Java虚拟机运行时数据区

其中 方法区 是线程共享的, 虚拟机栈 本地方法栈 程序计数器 是线程私有的。

什么情况下会发生栈溢出?

栈溢出(StackOverflowError)发生在程序调用栈的深度超过 JVM 允许的最大深度时。栈溢出的本质是因为线程的栈空间不足,导致无法再为新的栈帧分配内存。

二哥的Java进阶之路:栈帧

当一个方法被调用时,JVM 会在栈中分配一个栈帧,用于存储该方法的执行信息。如果方法调用嵌套太深,栈帧不断压入栈中,最终会导致栈空间耗尽,抛出 StackOverflowError。

最常见的栈溢出场景是递归调用,尤其是没有正确的终止条件,导致递归无限进行。

class StackOverflowExample {
    public static void recursiveMethod() {
        // 没有终止条件的递归调用
        recursiveMethod();
    }

    public static void main(String[] args) {
        recursiveMethod();  // 导致栈溢出
    }
}

另外,如果方法中定义了特别大的局部变量,栈帧会变得很大,导致栈空间更容易耗尽。

public class LargeLocalVariables {
    public static void method() {
        int[] largeArray = new int[1000000];  // 大量局部变量
        method();  // 递归调用
    }

    public static void main(String[] args) {
        method();  // 导致栈溢出
    }
}

垃圾回收的过程是什么?

Java 的垃圾回收过程主要分为标记存活对象、清除无用对象、以及内存压缩/整理三个阶段。不同的垃圾回收器在执行这些步骤时会采用不同的策略和算法。

说一下Spring和Springboot之间有什么差异?

Spring Boot 是 Spring Framework 的一个扩展,提供了一套快速配置和开发的机制,可以帮助我们快速搭建 Spring 项目的骨架,提高生产效率。

特性 Spring Framework Spring Boot
目的 提供企业级的开发工具和库 简化 Spring 应用的开发、配置和部署
配置方式 主要通过 XML 和注解等手动配置 提供开箱即用的自动配置
启动和运行 需要打成 war 包到 Tomcat 等容器下运行 已嵌入 Tomcat 等容器,打包成 JAR 文件直接运行
依赖管理 手动添加和管理依赖 使用 spring-boot-starter 简化依赖管理

自动配置怎么实现的?

在 Spring 中,自动装配是指容器利用反射技术,根据 Bean 的类型、名称等自动注入所需的依赖。

三分恶面渣逆袭:SpringBoot自动配置原理

在 Spring Boot 中,开启自动装配的注解是 @EnableAutoConfiguration

二哥的 Java 进阶之路:@EnableAutoConfiguration 源码

Spring Boot 为了进一步简化,直接通过 @SpringBootApplication 注解一步搞定,这个注解包含了 @EnableAutoConfiguration 注解。

二哥的 Java 进阶之路:@SpringBootApplication源码

对MySQL事务的理解

事务是一个或多个 SQL 语句组成的一个执行单元,这些 SQL 语句要么全部执行成功,要么全部不执行,不会出现部分执行的情况。事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

事务的主要作用是保证数据库操作的一致性,即事务内的操作,要么全部成功,要么全部失败回滚,不会出现中间状态。这对于维护数据库的完整性和一致性非常重要。

事务具有四个基本特性,也就是通常所说的 ACID 特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

三分恶面渣逆袭:事务四大特性

事务里一致性怎么理解?

一致性确保事务从一个一致的状态转换到另一个一致的状态。

比如在银行转账事务中,无论发生什么,转账前后两个账户的总金额应保持不变。假如 A 账户(100 块)给 B 账户(10 块)转了 10 块钱,不管成功与否,A 和 B 的总金额都是 110 块。

对MySQL索引的理解

数据库文件是存储在磁盘上的,磁盘 I/O 是数据库操作中最耗时的部分之一。没有索引时,数据库会进行全表扫描(Sequential Scan),这意味着它必须读取表中的每一行数据来查找匹配的行(时间效率为 O(n))。当表的数据量非常大时,就会导致大量的磁盘 I/O 操作。

有了索引,就可以直接跳到索引指示的数据位置,而不必扫描整张表,从而大大减少了磁盘 I/O 操作的次数。

MySQL 的 InnoDB 存储引擎默认使用 B+ 树来作为索引的数据结构,而 B+ 树的查询效率非常高,时间复杂度为 O(logN)。

索引文件相较于数据库文件,体积小得多,查到索引之后再映射到数据库记录,查询效率就会高很多。

索引就好像书的目录,通过目录去查找对应的章节内容会比一页一页的翻书快很多。

三分恶面渣逆袭:索引加快查询远离

什么情况下索引失效?

  • 在索引列上使用函数或表达式 :如果在查询中对索引列使用了函数或表达式,那么索引可能无法使用,因为数据库无法预先计算出函数或表达式的结果。例如: SELECT * FROM table WHERE YEAR(date_column) = 2021
  • 使用不等于( <> )或者 NOT 操作符:这些操作符通常会使索引失效,因为它们会扫描全表。
  • 使用 LIKE 操作符,但是通配符在最前面 :如果 LIKE 的模式串是以“%”或者“_”开头的,那么索引也无法使用。例如: SELECT * FROM table WHERE column LIKE '%abc'
  • OR 操作符 :如果查询条件中使用了 OR,并且 OR 两边的条件分别涉及不同的索引,那么这些索引可能都无法使用。
  • 联合索引不满足最左前缀原则时,索引会失效。

Redis常见数据结构

Redis 有五种基本数据类型,这五种数据类型分别是:string(字符串)、hash(哈希)、list(列表)、set(集合)、sorted set(有序集合,也叫 zset)。

三分恶面渣逆袭:Redis基本数据类型







请到「今天看啥」查看全文


推荐文章
软件小妹  ·  又可白嫖了,安卓和iOS均可使用!
昨天
软件小妹  ·  又可白嫖了,安卓和iOS均可使用!
昨天
湖北商务  ·  正式开放!阿里巴巴落子武汉
2 天前
湖北商务  ·  正式开放!阿里巴巴落子武汉
2 天前
风动幡动还是心动  ·  不多说了,赶紧上车
2 天前
风动幡动还是心动  ·  不多说了,赶紧上车
2 天前
国家林业和草原局  ·  新闻联播:我国古树名木保护取得积极进展
3 天前
国家林业和草原局  ·  新闻联播:我国古树名木保护取得积极进展
3 天前