专栏名称: 沉默王二
技术文通俗易懂,吹水文风趣幽默。学 Java,认准二哥的网站 javabetter.cn
目录
相关文章推荐
产业互联网大视野  ·  报名火热!产业互联网全产业链企业交流晚宴引爆行业 ·  昨天  
现代财经  ·  《现代财经-早读早分享》2024年10月11 ... ·  昨天  
现代财经  ·  《现代财经-早读早分享》2024年10月11 ... ·  昨天  
投行业务资讯  ·  IPO案例:销售返利款会计处理 ·  4 天前  
51好读  ›  专栏  ›  沉默王二

比亚迪开奖了,真的很惊喜。。

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

正文

大家好,我是二哥呀。

比亚迪这次开奖和去年,甚至前年的情况差不多,双 211 以上的有说点击就送,也有说不再严格按照学历定级,即便是 C9 硕,也可能给到一个非常惊喜的薪资——13k。

我这里简单给大家盘点一下,放在了 Java 面试指南的《25 届 24 届薪资一览表》中,希望给 25 届的小伙伴一点参考和借鉴。

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

大致就是:

  • 211 本、985 本能开到 9k-15k(包括硕)
  • 985 硕能开到 18k(c9 居多)
  • 20k 以上的凤毛麟角(海龟、清北)

之前的文章留言区也有读者反馈,本科双一流或者双非,但硕士很顶的也无济于事,简历投了几乎没信,由此可以推断出比亚迪今年的秋招要求确实比往年升级了很多。

我在旧文中也给出了详细的原因,简单说就是比亚迪这几年的发展远超预期,不仅销量爆炸式的增长,研发人数也爆炸式的增长,不再是以前的笛子了。

我们就从技术的角度来对比一下,点击就送时比亚迪问到的面试题,简单到爆,我感赌一百根辣条,只要你把面渣逆袭中 Java 后端四大件的高频题背完,甚至都不用背完,就能吊打面试官。

再对比一下今年的面试题,难度已经完全不输大厂了,我只能说【点击就送】已成往事(🤣)。

那今天我们就以 Java 面试指南中收录的同学 12 已 OC 但已拒的 Java 后端面试来看看,比亚迪的技术面试官现在都喜欢问哪些问题,今年打算冲比亚迪保底的小伙伴可以做到心中有数。

背八股就认准三分恶的面渣逆袭

比亚迪同学12面经

java的集合介绍一下

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

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

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

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

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

数组和链表的区别

  • 数组在内存中占用的是一块连续的存储空间,因此我们可以通过数组下标快速访问任意元素。数组在创建时必须指定大小,一旦分配内存,数组的大小就固定了。
  • 链表的元素(节点)存储在内存中的任意位置,每个节点通过指针(引用)指向下一个节点。链表不需要指定大小,可以在运行时动态变化。
数组和链表的区别

map的同步和非同步

Hashtable 是 Map 接口的一个早期的同步实现,它的所有方法都是同步的,即每个方法都用 synchronized 关键字修饰,以确保线程安全。

随着 JDK 版本的升级,Java 提供了更好的线程安全 Map 实现,如 ConcurrentHashMap。

如果是在单线程环境下,可以使用 HashMap。

java的反射

反射允许 Java 在运行时检查和操作类的方法和字段。通过反射,可以动态地获取类的字段、方法、构造方法等信息,并在运行时调用方法或访问字段。

比如创建一个对象是通过 new 关键字来实现的:

Person person = new Person();

Person 类的信息在编译时就确定了,那假如在编译期无法确定类的信息,但又想在运行时获取类的信息、创建类的实例、调用类的方法,这时候就要用到反射。

反射功能主要通过 java.lang.Class 类及 java.lang.reflect 包中的类如 Method, Field, Constructor 等来实现。

三分恶面渣逆袭:Java反射相关类

比如说我们可以装来动态加载类并创建对象:

String className = "java.util.Date";
Class> cls = Class.forName(className);
Object obj = cls.newInstance();
System.out.println(obj.getClass().getName());

代理介绍一下,jdk动态代理和cglib的区别

Spring 的 AOP 是通过动态代理来实现的,动态代理主要有两种方式:JDK 动态代理和 CGLIB 代理。

①、JDK 动态代理是基于接口的代理,只能代理实现了接口的类。使用 JDK 动态代理时,Spring AOP 会创建一个代理对象,该代理对象实现了目标对象所实现的接口,并在方法调用前后插入横切逻辑。

优点:只需依赖 JDK 自带的 java.lang.reflect.Proxy 类,不需要额外的库;缺点:只能代理接口,不能代理类本身。

示例代码:

public interface Service {
    void perform();
}

public class ServiceImpl implements Service {
    public void perform() {
        System.out.println("Performing service...");
    }
}

public class ServiceInvocationHandler implements InvocationHandler {
    private Object target;

    public ServiceInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method");
        Object result = method.invoke(target, args);
        System.out.println("After method");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        Service service = new ServiceImpl();
        Service proxy = (Service) Proxy.newProxyInstance(
            service.getClass().getClassLoader(),
            service.getClass().getInterfaces(),
            new ServiceInvocationHandler(service)
        );
        proxy.perform();
    }
}

②、CGLIB 动态代理是基于继承的代理,可以代理没有实现接口的类。使用 CGLIB 动态代理时,Spring AOP 会生成目标类的子类,并在方法调用前后插入横切逻辑。

图片来源于网络

优点:可以代理没有实现接口的类,灵活性更高;缺点:需要依赖 CGLIB 库,创建代理对象的开销相对较大。

示例代码:

public class Service {
    public void perform() {
        System.out.println("Performing service...");
    }
}

public class ServiceInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Service.class);
        enhancer.setCallback(new ServiceInterceptor());

        Service proxy = (Service) enhancer.create();
        proxy.perform();
    }
}

mysql的隔离级别有哪些

事务的隔离级别定了一个事务可能受其他事务影响的程度,MySQL 支持的四种隔离级别分别是:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。

三分恶面渣逆袭:事务的四个隔离级别

索引有哪些,区别是什么

二哥的 Java 进阶之路:索引类型

我就从数据结构上来说说它们的区别吧。

①、B+树索引:最常见的索引类型,一种将索引值按照一定的算法,存入一个树形的数据结构中(二叉树),每次查询都从树的根节点开始,一次遍历叶子节点,找到对应的值。查询效率是 O(logN)。

也是 InnoDB 存储引擎的默认索引类型

B+ 树是 B 树的升级版,B+ 树中的非叶子节点都不存储数据,只存储索引。叶子节点中存储了所有的数据,并且构成了一个从小到大的有序双向链表,使得在完成一次树的遍历定位到范围查询的起点后,可以直接通过叶子节点间的指针顺序访问整个查询范围内的所有记录,而无需对树进行多次遍历。这在处理大范围的查询时特别高效。

一颗剽悍的种子:B+树的结构

②、Hash 索引:基于哈希表的索引,查询效率可以达到 O(1),但是只适合 = 和 in 查询,不适合范围查询。

Hash 索引在原理上和 Java 中的 HashMap 类似,当发生哈希冲突的时候也是通过拉链法来解决。

业余码农:哈希索引

索引失效场景

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

索引优化的思路

①、选择合适的索引类型

  • 如果需要等值查询和范围查询,请选择 B+树索引。
  • 如果是用于处理文本数据的全文搜索,请选择全文索引。

②、创建适当的索引

  • 创建组合索引时,应将查询中最常用、区分度高的列放在前面。对于查询条件 WHERE age = 18 AND gender = '女' AND city = '洛阳',如果 age 列的值相对较为分散,可以优先考虑将 age 放在组合索引的第一位。
  • 使用 SELECT 语句时,尽量选择覆盖索引来避免不必要的回表操作,也就是说,索引中包含了查询所需的所有列;但要注意,覆盖索引的列数不宜过多,否则会增加索引的存储空间。

怎么解决redis和mysql的缓存一致性问题

在技术派实战项目中,我采用的是先写 MySQL,再删除 Redis 的方式来保证缓存和数据库的数据一致性。

技术派教程

对于第一次查询,请求 B 查询到的缓存数据是 10,但 MySQL 被请求 A 更新为了 11,此时数据库和缓存不一致。

但也只存在这一次不一致的情况,对于不是强一致性的业务,可以容忍。

当请求 B 第二次查询时,因为请求 A 更新完数据库把缓存删除了,所以请求 B 这次不会命中缓存,会重新查一次 MySQL,然后回写到 Redis。

缓存和数据库又一致了。

Spring的事务用过吗,在项目里面怎么使用的

在 Spring 中,事务管理可以分为两大类:声明式事务管理和编程式事务管理。

三分恶面渣逆袭:Spring事务分类

在技术派项目中,我会使用 @Transactional 注解的方式来实现声明式事务管理。

@Service
public class AccountService {
    @Autowired
    private AccountDao accountDao;

    @Transactional
    public void transfer(String out, String in, Double money) {
        // 转出
        accountDao.outMoney(out, money);
        // 转入
        accountDao.inMoney(in, money);
    }
}

ending

一个人可以走得很快,但一群人才能走得更远。二哥的编程星球已经有 6300 多名球友加入了,如果你也需要一个良好的学习环境,戳链接 🔗 加入我们吧。这是一个 编程学习指南 + Java 项目实战 + LeetCode 刷题 + 简历精修 的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。

两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的学习资源,相信能帮助你走的更快、更稳、更远

欢迎点击左下角阅读原文了解二哥的编程星球,这可能是你学习求职路上最有含金量的一次点击。

最后,把二哥的座右铭送给大家:没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。共勉 💪。