news 2026/10/3 11:38:10

面渣逆袭:Java基础高频面试题深度解析与底层原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
面渣逆袭:Java基础高频面试题深度解析与底层原理

面渣这个称呼,第一次看到的时候我愣了几秒,然后苦笑——这不就是当年的自己吗。面试Java基础岗,被面试官从HashMap问到String,再从集合问到多线程,每个问题都“看着眼熟、说着卡壳”,笔试能写,嘴上一问就废。后来我把高频基础题全部重新过了一遍,不只背结论,还把“为什么”彻底搞懂,才慢慢从面渣变成了面霸。这篇笔记就是那段时间沉淀下来的东西,重点不是罗列答案,而是帮你建立一套“说到哪个知识点都能多讲两层”的底气。

适合正在准备Java面试的应届生、转行的人,也适合工作一两年但基础不够扎实、想回头补课的同学。内容聚焦在面试中最常踩坑的基础模块:语法陷阱、集合底层、JVM内存、异常反射、动态代理、多线程基础。每一块我都会按“面试官怎么问、怎么答能加分、坑在哪里”的顺序拆给你看。

1. 开场先泼冷水:基础题挂掉的人,大多不是不会,是“只会一层”

很多人在牛客上看面经,背得滚瓜烂熟:HashMap底层是数组加链表,ArrayList底层是数组,String是不可变类……但一被追问就露馅。为什么?因为只记住了“是什么”,没搞懂“为什么”。面试官问基础题,真正想看的不是你背了多少,而是你有没有深挖过一层。

举个真实场景。面试官问:“ArrayList和LinkedList有什么区别?”大多数人张口就来:一个数组一个链表,查询快慢不同。然后面试官接着问:“那为什么实际开发中,LinkedList明明插入是O(1),却很少用它来做频繁插入?”这个追问就能刷掉一大半人。

再比如问“==和equals有什么区别”,标准答案谁都会背。但如果面试官加一句:“那Integer a = 100; Integer b = 100;为什么a == b是true,换成200就变false?”很多人就懵了。这些不是偏题怪题,恰恰是Java基础最核心的“底层直觉”。

所以这篇我不按教科书目录走,而是按面试官的真实提问链来组织。每个知识点都补上“再深一层”的部分,让你面对追问的时候,也能从容接住。

1.1 先搞清“面渣”到底渣在哪里

我复盘了自己和周围朋友的面试经历,发现基础面挂掉通常有三个原因:

  • 背了结论,但不清楚底层机制。比如知道HashMap是数组加链表,但不知道链表什么时候转红黑树、为什么转。
  • 知道API,但不理解设计意图。比如知道ConcurrentHashMap是线程安全的,但说不清它和Hashtable在并发策略上的本质差异。
  • 懂单个知识点,串不起来。比如单独问String、StringBuilder、StringBuffer都能说两句,但一问“为什么用+拼接字符串性能差”,就答不上来,因为没把字符串不可变性、常量池、内存分配串成一条线。

这篇文章就是冲着这三个“渣点”去的。看完之后,你再看基础题,会发现很多答案其实可以自己推出来。

2. 语法陷阱与面向对象:最容易翻车的“送分题”才是分水岭

基础语法题在面试里往往被当作“热身题”,但这几道热身题恰恰是分水岭。答得漂亮,面试官会默认你基础扎实;答得含糊,后面就算八股文背得再熟练,可信度也会打折扣。

2.1 Integer缓存与自动装箱:两行代码能问出一串考点

这个考点几乎年年必考,因为它一个人就串起了自动装箱、常量池、equals与==的区别三个知识点。

Integer a = 100; Integer b = 100; System.out.println(a == b); // true Integer c = 200; Integer d = 200; System.out.println(c == d); // false

第一段输出true,第二段输出false。原因在于Integer内部维护了一个缓存数组,默认缓存-128到127之间的整数。当你用Integer.valueOf()或者直接赋值时,如果值在这个范围内,直接返回缓存对象,所以a和b指向同一个对象。超出范围则每次都会new Integer(),c和d是两个不同对象,==比较地址自然不等。

面试到这里还没完,面试官会继续问:这个缓存范围可以调吗?答案是可以,通过JVM启动参数-XX:AutoBoxCacheMax可以修改上限。再追一层:为什么设计这个缓存?因为小整数在业务中最常用,缓存可以减少对象创建,提升性能和内存利用率。

回答的时候如果你能主动补一句“缓存上限默认127,但可以通过JVM参数调整,IntegerCache类里有一个high字段”,面试官会明显眼前一亮。

2.2 equals与hashCode:为什么重写equals必须重写hashCode

这个问题的正确回答其实分三层:

第一层是约定。Object规范里写明:如果两个对象根据equals方法相等,那么它们的hashCode必须相等。反过来不成立,hashCode相等不代表对象相等。

第二层是数据结构。HashMap、HashSet这些基于哈希的集合,存数据时先用hashCode定位桶,再用equals确认是否相同。如果只重写equals不重写hashCode,就会出现“两个业务上相等的对象,hashCode不一样,被放进同一个Set的两个不同桶里”,直接破坏集合的去重逻辑。

第三层是实际案例。最常见的是用User对象做Set去重或Map的key。你只重写了equals,没重写hashCode,那么HashSet<User>里add两个id相同的用户,会变成两个元素。这个坑在真实项目里出现频率极高,尤其在做数据同步、Excel导入这类场景。

2.3 重载与重写:多态背后的“哪个方法被调用”

重载和重写这个知识点,面试官喜欢用代码题来考,重点在于理解“编译期确定还是运行期确定”。

public class Animal { public void eat() { System.out.println("animal eat"); } } public class Dog extends Animal { public void eat() { System.out.println("dog eat"); } } Animal a = new Dog(); a.eat(); // 输出 dog eat

方法重写是运行期动态绑定,JVM根据实际对象类型来决定调用哪个方法。而方法重载是编译期静态绑定的,看你声明参数的类型:

public void print(String s) { ... } public void print(Object o) { ... } print(null); // 编译报错,因为null既匹配String也匹配Object,编译器无法区分

这种细节题很能考察基础是否扎实。另外还会延伸一个问题:能不能通过反射调用private方法?这个放到反射章节一起说。

2.4 枚举到底是个什么东西

热词里有“java枚举类型的使用”。面试里关于枚举,最容易被问的是“枚举本质是什么”。答案:枚举本质上是一个继承了java.lang.Enum的类,每个枚举常量都是该类的一个静态final实例。

值得记住的两个点:

  • 枚举可以用在switch里,语法层是支持的,编译器会帮你做转换。
  • 枚举是实现单例模式的一种安全方式,因为JVM保证枚举实例只会被实例化一次,天然防反射、防序列化破坏。

面试时可以主动说:“我一般用枚举来表示状态码或者固定参数集合,比如订单状态、用户角色。”一句话就把理论落到了实际场景。

3. 集合框架:从“背API”到“讲底层”的跨越

集合是Java基础面试的绝对C位。这一块有太多可以问的深挖点,但核心逻辑其实是一致的:数据结构决定性能,性能决定使用场景。

3.1 HashMap深度解析:为什么它永远稳坐面渣题头把交椅

HashMap之所以成为经典题,是因为它把哈希、链表、红黑树、扩容、并发问题全部串在了一起。

先捋一遍put流程:

  1. 计算key的hash值,具体实现是(h = key.hashCode()) ^ (h >>> 16),把高16位和低16位做异或,目的是让高位也参与散列。
  2. 根据(n - 1) & hash定位到数组桶的位置。
  3. 如果桶为空,直接放进去。
  4. 如果桶不为空,判断key是否相同,相同则替换value。
  5. 否则说明发生了哈希碰撞,追加到链表或红黑树中。
  6. 链表长度达到8且数组长度达到64时,链表转红黑树。
  7. 元素个数超过阈值(容量*负载因子)时,触发扩容。

常见追问和加分答法:

  • 为什么链表转红黑树的阈值是8?因为链表长度遵循泊松分布,在负载因子0.75的情况下,链表长度到8的概率已经极低。选8是时间与空间的权衡,转成红黑树后查询从O(n)降到O(log n),但红黑树节点占用空间是链表节点的两倍,所以只在极端情况下才转。
  • 为什么数组容量必须是2的幂?因为计算桶位置用的是(n - 1) & hash而不是取模运算,2的幂减1后二进制全是1,位与运算能均匀分布、性能更快。
  • 扩容时为什么要重新计算位置?JDK 1.7是rehash,JDK 1.8优化后,根据(e.hash & oldCap)判断,是0就留在原位,是1就移到“原位+oldCap”,性能高很多。

3.2 ArrayList和LinkedList:别再只回答“数组vs链表”

这个题如果只答数组和链表的区别,只能拿基础分。要拿高分,得从三个维度展开。

第一个维度是底层结构。ArrayList底层是Object数组,LinkedList底层是双向链表。

第二个维度是CRUD操作的时间复杂度。ArrayList随机访问是O(1),插入删除是O(n);LinkedList头尾插入是O(1),随机访问是O(n)。这一层大多数人都能答到。

第三个维度是内存占用。ArrayList扩容时会一次性扩大1.5倍,LinkedList每个节点除了数据还要存前后指针,24字节起步。所以即使“LinkedList插入快”,在真实场景里大部分业务还是用ArrayList,因为绝大多数操作其实是遍历和读。

加分回答:可以直接说“实际开发中LinkedList用得很少,因为内存开销大、缓存不友好,真正需要频繁头尾插入的场景,更推荐ArrayDeque,它底层是循环数组,各方面性能都比LinkedList好”。这一句就能拉开和其他候选人的差距。

3.3 线程安全的集合:从Hashtable到ConcurrentHashMap

这个问题考察的是对并发容器演进的理解。

Hashtable之所以慢,是因为它把所有方法都加了synchronized,等于对整张表加锁,并发再高也只有一个线程能操作。

ConcurrentHashMap在JDK 1.7用的是分段锁,把数据分成多段,每段独立加锁。JDK 1.8改为CAS加synchronized,锁粒度降为单个数组桶,并且取消了分段锁的结构。读操作大多无锁,写操作只锁当前桶。这带来两个结论:并发度更高,且size()这类方法通过累加计数器和部分重试机制来保证一定准确性,但并不保证强一致。

面试官还可能追问:“HashMap在并发场景会出什么问题?”回答:JDK 1.7头插法扩容时可能形成环形链表,导致get死循环;JDK 1.8改尾插法后不会死循环,但会丢失数据。所以并发场景一律用ConcurrentHashMap。

4. JVM内存与字符串:一道题可以串起整个Java基础

String相关的问题在Java面试中出现频率极高,而且它天然能把“不可变性”“常量池”“内存模型”串起来回答。

4.1 String、StringBuilder、StringBuffer:三者的本质差异

常规回答是:String不可变,StringBuffer线程安全,StringBuilder非线程安全。但这个回答不够。

你要补充的是“为什么String设计成不可变”。原因有三:

  • 安全。字符串被大量用于类名、文件路径、网络地址等场景,如果可变化,会带来严重风险。
  • 缓存。不可变对象的hashCode可以放心缓存,这也是String适合做HashMap的key的原因。
  • 常量池复用。只有不可变,才能放心让多个变量引用同一个字符串对象,节省内存。

StringBuffer和StringBuilder内部都是可变字符数组,区别在于方法是否加了synchronized。实际开发中,单线程拼接字符串优先用StringBuilder,性能最优。

4.2 字符串拼接的性能陷阱:别小看一个加号

String a = "a" + "b" + "c";这行代码,编辑器层面会直接优化成"abc",因为都是编译期常量。

但如果你写:

String prefix = "a"; String result = prefix + "b" + "c";

prefix是变量,编译期无法确定值。在JDK 8中,这种拼接会在底层创建StringBuilder来执行追加操作。循环里拼接的问题就来了:每次循环都会new一个新的StringBuilder,循环1万次,就new了1万个对象,GC压力暴增。

所以循环拼接的正确姿势应该是在循环外创建一个StringBuilder复用。

4.3 JVM内存与字符串常量池的位置

这是进阶问题,很多面渣挂在这里。要答好,需要知道不同JDK版本的区别:

  • JDK 1.6及之前:字符串常量池在方法区(永久代)。
  • JDK 1.7开始:字符串常量池挪到堆中。
  • JDK 1.8:永久代被元空间取代,字符串常量池依然在堆。

然后引出intern()方法。intern()的作用是:如果字符串常量池中已有相同内容的字符串,直接返回池中的引用;否则把当前字符串加入池中并返回引用。

经典代码题:

String s1 = new String("abc"); // 创建两个对象:堆中一个,常量池一个(如果池中没有) String s2 = s1.intern(); System.out.println(s1 == s2); // false,s1是堆对象,s2是池中对象

这块能把JVM内存模型、字符串常量池、对象创建机制全部串起来,是面试官最爱问的“综合题”。

5. 异常、反射与动态代理:Java“法术”的底层根基

异常体系、反射、动态代理这三个点,单独看不难,但它们连在一起,正好就是Spring等框架的核心基础。

5.1 异常体系与try-with-resources

先明确体系:Throwable有两个子类,Error和Exception。Error表示JVM层面的严重问题,程序无法处理;Exception分为受检异常(checked exception)和非受检异常(unchecked exception,即RuntimeException及其子类)。

受检异常在编译期就必须处理,比如IOException、SQLException。非受检异常不需要显式捕获,比如NullPointerException、ClassCastException。实际开发中,业务异常一般继承RuntimeException,这样可以避免方法签名上堆满throws,让上层统一通过全局异常处理器捕获。

JDK 7引入的try-with-resources是必须掌握的:

try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) { String line = reader.readLine(); }

所有实现了AutoCloseable接口的资源,都能自动关闭。不再需要手写finally来close。

5.2 反射:如何拿到一个类的全部信息

反射是Java动态机制的核心。获取Class对象的三种方式:

  • 类名.class
  • 对象.getClass()
  • Class.forName("全限定类名")

反射能干的事情很多:获取构造器、方法、字段,甚至调用私有方法。

Class<?> clazz = Class.forName("com.example.User"); Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class); constructor.setAccessible(true); // 突破private限制 Object obj = constructor.newInstance("小明", 18);

面试追问点:为什么框架里要用反射?因为框架在编译期不知道用户会传什么类进来,只能在运行期通过反射来动态创建对象、调用方法。Spring的IoC容器就是典型代表,通过读取配置或注解,反射创建Bean。

再追问一层:反射为什么性能差?因为反射时JVM无法进行内联优化,还要做大量的权限检查、类型检查。但现在JDK也在优化,比如MethodHandle和LambdaMetafactory的使用,很多场景下性能损耗已经明显下降。

5.3 动态代理:为什么必问JDK与CGLIB的区别

动态代理这个问题,本质是考察你知不知道Spring AOP的底层原理。

先说JDK动态代理。它要求被代理的类必须实现接口。原理是运行期用Proxy.newProxyInstance()生成一个实现同样接口的代理类,然后在InvocationHandler的invoke方法里统一增强逻辑。

UserService proxy = (UserService) Proxy.newProxyInstance( UserService.class.getClassLoader(), new Class[]{UserService.class}, (proxyObj, method, args) -> { System.out.println("前置增强"); Object result = method.invoke(target, args); System.out.println("后置增强"); return result; } );

CGLIB不同,它通过继承目标类来生成代理子类,所以不要求实现接口。Spring在实现AOP时的选择逻辑是:目标类实现了接口就用JDK动态代理,没实现接口就用CGLIB。Spring Boot 2.x之后默认代理方式改成了CGLIB,这个细节值得提一下,面试官会认可你关注版本变更。

常见追问:JDK动态代理和CGLIB各自的劣势是什么?JDK动态代理需要接口,CGLIB是继承生成子类,所以final类或final方法无法被代理。

6. 多线程基础三连:创建方式、状态流转、等待策略

多线程是Java基础面试的压轴大菜。基础阶段不需要你把JUC全部源码背下来,但线程的创建、状态、常用协作工具必须滚瓜烂熟。热词里“java线程等待都完成”出现频率特别高,这块好好看。

6.1 三种创建方式,哪种最“正经”

创建线程的方式严格说只有一种:new Thread()。Runnable、Callable都是任务逻辑的载体,最终都要包进Thread里执行。

// 方式一:继承Thread class MyThread extends Thread { @Override public void run() { ... } } // 方式二:实现Runnable Thread t = new Thread(() -> { ... }); // 方式三:实现Callable + FutureTask FutureTask<Integer> task = new FutureTask<>(() -> 42); Thread t = new Thread(task); Integer result = task.get();

面试官会问“这三种方式有什么区别”。回答思路:

  • 继承Thread的缺点是单继承限制,不推荐。
  • 实现Runnable没有返回值,适合不需要结果的任务。
  • Callable有返回值,能抛异常,适合需要拿到执行结果的场景。
  • 真实项目中不会直接new Thread,而是使用线程池,理由是可复用线程、控制并发数、统一管理生命周期。

6.2 线程状态与wait/sleep的微妙区别

线程的六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。

面试高频追问是“wait()和sleep()有什么区别”。我从五个维度理清了:

  • wait()来自Object类,sleep()来自Thread类。
  • wait()会释放锁,sleep()不会。
  • wait()必须在同步代码块中调用,sleep()任意位置都可以。
  • wait()需要被唤醒,sleep()到时间自动醒。
  • 两者都会抛出InterruptedException,进入WAITING或TIMED_WAITING状态。

补充一点知识的连贯性:notify()和notifyAll()的区别在于是唤醒一个线程还是全部唤醒。这些都属于“线程协作”的基础机制。

6.3 如何优雅地等待所有线程完成

热词里“java线程等待都完成”的搜索率很高,说明这个点确实难倒了不少人。最常见的做法是Thread.join(),它让当前线程阻塞等待目标线程终止。

Thread t1 = new Thread(task1); Thread t2 = new Thread(task2); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("t1和t2都执行完了");

但真正常用的其实是CountDownLatch。它的设计逻辑是:初始化一个计数器,每个线程执行完就countDown()一次,主线程调用await()阻塞,直到计数器归零。

CountDownLatch latch = new CountDownLatch(3); for (int i = 0; i < 3; i++) { new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) {} latch.countDown(); }).start(); } latch.await(); System.out.println("三个线程都完成了");

CountDownLatch是一次性的,需要用CyclicBarrier可以实现循环复用。这两兄弟的区别也可以作为加分项:CountDownLatch是“倒计数门闩”,一次性的;CyclicBarrier是“循环屏障”,所有线程到达屏障后放行,然后能重新使用。

6.4 ThreadLocal:面试爱问的内存泄漏问题

ThreadLocal也是Java基础面试的高频点,核心考点是两个:作用原理和内存泄漏。

作用原理:每个线程内部维护一个ThreadLocalMap,key是ThreadLocal对象(弱引用),value是存入的副本值。所以ThreadLocal可以让每个线程拥有自己独立的变量副本,实现线程隔离。

内存泄漏问题:key是弱引用,当ThreadLocal外部强引用被清除后,key会被GC回收,变成key为null但value还存在。如果线程一直存活(比如线程池中的线程),value就永远无法被回收。解决方案是每次用完调用remove()。

面试作答时能说出“因为key是弱引用而value是强引用,所以存在Entry内存泄漏问题,推荐在finally中调用remove”这个层次,就已经超越了大部分候选人。

7. 面渣逆袭的答题方法与面试心态

技术点讲完了,最后聊点实际的。很多人基础不差,但面试时表达混乱。我自己的经验是:技术面试的答题节奏是有方法论的。

7.1 三层答题法:结论、原理、场景

回答任何一个技术问题,尽量按照“结论-原理-场景”三层结构组织。

举例:面试官问“HashMap为什么线程不安全”。

  • 结论:并发put时可能出现数据覆盖,JDK 1.7还可能形成环形链表导致死循环。
  • 原理:HashMap的put方法没有加锁,多线程同时操作同一个桶时,后写覆盖先写;扩容时多个线程同时rehash,可能导致链表环化。
  • 场景:所以并发场景必须使用ConcurrentHashMap,这也是面试官想听到的落地点。

这种结构的好处是,你永远有话说,而且说到最后一定会把话题引向下一个你能熟练展开的知识点,相当于把面试节奏握在自己手里。

7.2 主动“挖坑”引导面试官

面渣和面霸的另一个差距,是会不会引导面试官问自己准备好的内容。

当你发现面试官问了一个你不太熟悉的问题,可以在回答末尾把话题主动引到擅长的方向。比如面试官问的是“JVM内存模型”,但你不太熟,可是你熟悉类加载机制,可以这么说:“JVM内存模型这块我主要关注运行时常量池和字符串常量池的关系,之前遇到过一个关于intern()的线上问题……”道完歉,话锋一转就转到了你能展开的内容。这不是耍滑头,而是合理的沟通技巧——没人要求你必须每个问题都答满分。

7.3 关于基础面试的最后一个建议

准备期间,每学一个知识点,都问自己三个问题:它解决了什么问题?它的底层原理是什么?它和相关的知识点有什么异同?如果都能答上来,就去模拟口述一遍,说到自己觉得顺畅为止。等到面试现场,你会发现自己根本不用背答案,因为答案就是你自己的逻辑。

我从“听到基础题就心虚”到“希望面试官多问基础题”,就是靠这一套方法翻的身。基础扎实之后,你会发现后面学并发、学JVM、学Spring,都会顺畅很多。希望下一场面试结束,刷到“面渣逆袭”这条热搜的人,变成了你。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 11:36:55

OpenCV实战项目全解析:从环境搭建到物体识别与图像处理

1. 项目全景图谱&#xff1a;52个项目的分级与选型 如果你和我一样&#xff0c;是看了某个"52个OpenCV实战项目"合集却不知道从哪下手才开始接触图像处理的&#xff0c;我特别理解你现在的状态&#xff1a;收藏了、下载了、然后就没有然后了。这里面有相当大一部分原…

作者头像 李华
网站建设 2026/10/3 11:36:53

把DeepSeek装进WPS:JS宏直连API实现AI润色翻译摘要

以前我在WPS里改方案&#xff0c;最烦的就是在浏览器和编辑器之间来回切。选中一段文字&#xff0c;复制到网页对话框&#xff0c;等AI结果&#xff0c;再复制回来&#xff0c;重新调格式……一天下来&#xff0c;这种机械操作能占掉大把时间。后来DeepSeek开放了API&#xff0…

作者头像 李华
网站建设 2026/10/3 11:34:34

superpowers工具集安装指南与Java开发效率提升实践

做过几年Java后端&#xff0c;又折腾过一阵子IDE插件和自动化流水线&#xff0c;我第一眼看到“superpowers”这个名字&#xff0c;以为又是哪个游戏Mod。直到点进项目页才发现&#xff0c;它其实是一套面向开发者的效率增强工具集——准确说&#xff0c;是一套能把“写代码、查…

作者头像 李华
网站建设 2026/10/3 11:32:59

多变量时序预测的跨变量交互建模:FACT细粒度卷积与动态权重机制解析

在真实的多变量时序预测项目里&#xff0c;我越来越感觉到一个容易被低估的问题&#xff1a;模型架构里的“跨变量交互”经常只是摆设。很多模型号称建模了多变量&#xff0c;实际上只是把多个序列硬塞进同一个MLP或Transformer&#xff0c;变量之间到底有没有交互、交互是否随…

作者头像 李华
网站建设 2026/10/3 11:29:13

阜阳AI内容生产实战指南:方言短剧、漫剧与婚礼视频本地化工作流

1. 这不是“AI课”&#xff0c;是阜阳本地内容生产者的实战工具包 “阜阳AI培训与AI内容创作&#xff1a;短剧、漫剧、婚礼视频的本地化应用指南”——这个标题里藏着三个被严重低估的真实需求&#xff1a; 第一&#xff0c;不是学AI&#xff0c;而是用AI解决手头正在做的活儿…

作者头像 李华
网站建设 2026/10/3 11:28:52

SGLang-Kunlun多芯插件机制:从架构设计到压测实践

SGLang-Kunlun这个组合&#xff0c;最近在推理优化圈子里讨论度不低。我做大模型推理压测和部署也有些年头&#xff0c;从早期vLLM一家独大&#xff0c;到后来SGLang凭借RadixAttention和结构化输出等特性抢了不少份额&#xff0c;再到现在各家推理框架都在往“多芯适配”方向使…

作者头像 李华