查看原文
其他

招银网络一面,抗揍40分钟,过啦!

沉默王二 沉默王二
2024-09-09

大家好,我是二哥呀。

招商银行网络科技也开始约面了,有牛友一面面了 40 分钟,面试体验很好,说答不上来会给讲解。

我看了一面的内容,确实比互联网大厂友好太多,不是那种纯粹的八股,反而带有一些很有深度的思考。

让天下所有的面渣都能逆袭

招银网络科技也是很多小伙伴心仪的对象,因为银行一般比较稳定,同时招银的研发也是比较贴合互联网公司,不至于进去后把技术这块丢了。

虽然有加班,但强度不算是特别大,能有一个比较好的平衡。那今天我们就以 Java 面试指南中收录的同学 9 招银网络一面为例,来看看招银的面试官都喜欢问哪些问题,好做到心中有数,面试不慌。

招银网络科技同学 9 一面面经

Java堆内存和栈内存的区别

堆属于线程共享的内存区域,几乎所有的对象都在堆上分配,生命周期不由单个方法调用所决定,可以在方法调用结束后继续存在,直到不再被任何变量引用,然后被垃圾收集器回收。

栈属于线程私有的内存区域,主要存储局部变量、方法参数、对象引用等,通常随着方法调用的结束而自动释放,不需要垃圾收集器处理。

Java设计模式中的开闭原则,里氏替换了解?

开闭原则(Open-Closed Principle, OCP),指软件实体应该对扩展开放,对修改关闭。这意味着一个类应该通过扩展来实现新的功能,而不是通过修改已有的代码来实现。

举个例子,在不遵守开闭原则的情况下,有一个需要处理不同形状的绘图功能类。

class ShapeDrawer {
    public void draw(Shape shape) {
        if (shape instanceof Circle) {
            drawCircle((Circle) shape);
        } else if (shape instanceof Rectangle) {
            drawRectangle((Rectangle) shape);
        }
    }
    
    private void drawCircle(Circle circle) {
        // 画圆形
    }
    
    private void drawRectangle(Rectangle rectangle) {
        // 画矩形
    }
}

每增加一种形状,就需要修改一次 draw 方法,这违反了开闭原则。正确的做法是通过继承和多态来实现新的形状类,然后在 ShapeDrawer 中添加新的 draw 方法。

// 抽象的 Shape 类
abstract class Shape {
    public abstract void draw();
}

// 具体的 Circle 类
class Circle extends Shape {
    @Override
    public void draw() {
        // 画圆形
    }
}

// 具体的 Rectangle 类
class Rectangle extends Shape {
    @Override
    public void draw() {
        // 画矩形
    }
}

// 使用开闭原则的 ShapeDrawer 类
class ShapeDrawer {
    public void draw(Shape shape) {
        shape.draw();  // 调用多态的 draw 方法
    }
}

里氏代换原则也被称为李氏替换原则(Liskov Substitution Principle, LSP),其规定任何父类可以出现的地方,子类也一定可以出现。

LSP 是继承复用的基石,只有当子类可以替换掉父类,并且单位功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。

这意味着子类在扩展父类时,不应改变父类原有的行为。例如,如果有一个方法接受一个父类对象作为参数,那么传入该方法的任何子类对象也应该能正常工作。

class Bird {
    void fly() {
        System.out.println("鸟正在飞");
    }
}

class Duck extends Bird {
    @Override
    void fly() {
        System.out.println("鸭子正在飞");
    }
}

class Ostrich extends Bird {
    // Ostrich违反了LSP,因为鸵鸟不会飞,但却继承了会飞的鸟类
    @Override
    void fly() {
        throw new UnsupportedOperationException("鸵鸟不会飞");
    }
}

在这个例子中,Ostrich(鸵鸟)类违反了 LSP 原则,因为它改变了父类 Bird 的行为(即飞行)。

说一说常用的设计模式

单例模式、策略模式和工厂模式。

在需要控制资源访问,如配置管理、连接池管理时经常使用单例模式。它确保了全局只有一个实例,并提供了一个全局访问点。

在有多种算法或策略可以切换使用的情况下,我会使用策略模式。像技术派实战项目中,我就使用策略模式对接了讯飞星火、OpenAI、智谱 AI 等多家大模型,实现了一个可以自由切换大模型基座的智能助手服务。

技术派派聪明 AI 助手

策略模式的好处是,不用在代码中写 if/else 判断,而是将不同的 AI 服务封装成不同的策略类,通过工厂模式创建不同的 AI 服务实例,从而实现 AI 服务的动态切换。

后面想添加新的 AI 服务,只需要增加一个新的策略类,不需要修改原有代码,这样就提高了代码的可扩展性。

Mysql联合索引的设计原则

在使用联合索引时,应当遵守最左前缀原则,或者叫最左匹配原则(最左前缀匹配原则)。

它指的是在使用联合索引时,查询条件从索引的最左列开始并且不跳过中间的列。

如果一个复合索引包含(col1, col2, col3),那么它可以支持 col1col1,col2col1, col2, col3 的查询优化,但不支持只有 col2 或 col3 的查询。

也就说,在进行查询时,如果没有遵循最左前缀,那么联合索引可能不会被利用,导致查询效率降低。

select for update 加锁有什么需要注意的

如果查询条件使用了索引(特别是主键索引或唯一索引),SELECT FOR UPDATE 会锁定特定的行,即行级锁,这样锁的粒度较小,不会影响未涉及的行或其他并发操作。

但如果查询条件未使用索引,SELECT FOR UPDATE 可能锁定整个表或大量的行,因为查询需要执行全表扫描。

假设有一张名为 orders 的表,包含以下数据:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    order_no VARCHAR(255),
    amount DECIMAL(10,2),
    status VARCHAR(50),
    INDEX (order_no)  -- order_no 上有索引
);

表中的数据是这样的:

idorder_noamountstatus
11000150.00pending
21000275.00pending
310003100.00pending
410004150.00completed
510005200.00pending

如果我们通过主键索引执行 SELECT FOR UPDATE,只会锁定特定的行:

START TRANSACTION;
SELECT * FROM orders WHERE id = 1 FOR UPDATE;
-- 对 id=1 的行进行操作
COMMIT;

由于 id 是主键,所以只会锁定 id=1 这行,不会影响其他行的操作。其他事务依然可以对 id = 2, 3, 4, 5 等行执行更新操作,因为它们没有被锁定。

如果使用 order_no 索引执行 SELECT FOR UPDATE,也只会锁定特定的行:

START TRANSACTION;
SELECT * FROM orders WHERE order_no = '10001' FOR UPDATE;
-- 对 order_no=10001 的行进行操作
COMMIT;

因为 order_no 上有索引,所以只会锁定 order_no=10001 这行,不会影响其他行的操作。

但如果查询 status='pending',而 status 上没有索引:

START TRANSACTION;
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;
-- 对 status=pending 的行进行操作
COMMIT;

查询需要执行全表扫描。在这种情况下,SELECT FOR UPDATE 可能会锁定表中所有符合条件的记录,甚至是整个表,因为 MySQL 需要检查每一行的 status。

这会影响表中的大部分记录,其他事务将无法修改这些记录,直到当前事务结束。

如何保证交易,订单等不会重复处理

在小规模系统中,数据库锁和唯一索引通常就足够保证交易订单不会被重复处理了;但在高并发的分布式系统中,还需要配合分布式锁来进一步保证。

数据量在500w的表,如何实现快速的全表模糊匹配

首先要使用合适的索引,LIKE 'pattern%' 可以使用普通索引,而 LIKE '%pattern%' 可以考虑 MySQL 的 FULLTEXT 索引;如果还不满足,可以使用 Elasticsearch。

内容来源

  • 星球嘉宾三分恶的面渣逆袭:https://javabetter.cn/sidebar/sanfene/nixi.html
  • 二哥的 Java 进阶之路(GitHub 已有 12000+star):https://javabetter.cn

ending

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

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

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

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

个人观点,仅供参考
继续滑动看下一个
沉默王二
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存