news 2026/10/9 4:15:50

Java静态代理与JDK动态代理:原理、对比与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java静态代理与JDK动态代理:原理、对比与实战

1. 代理模式:先搞清楚"代理"到底在解决什么问题

很多朋友一看到"静态代理和动态代理"这个标题,第一反应是去背概念:静态代理是编译期生成代理类,动态代理是运行期生成代理类。但说句实在话,如果你停留在这一步,那你确实还谈不上"懂"。因为代理模式真正要解决的,不是"怎么生成一个类",而是一个更本质的问题——如何在不修改原有代码的前提下,给某个对象的行为增加控制逻辑。

我在写业务代码时对这一点感触特别深。你想想,一个方法在真正执行之前,是不是经常要做一堆事:检查当前用户有没有权限、打印入参日志、统计接口耗时、开启事务、做参数校验……如果这些代码全部塞进业务方法里,会是什么后果?业务方法会越变越臃肿,而且每加一个横切需求,所有相关方法都得改一遍。更麻烦的是,一旦你把这些逻辑写死在某个方法里,之后想调整顺序或删除,就得动业务代码——这在很多生产环境里是不可接受的。

代理模式的做法是另外一种思路:我不动你原来的类,而是创建一个"中间人"对象,让它替调用方去访问原对象。调用方跟中间人打交道,中间人可以在转发请求给原对象之前或之后,插入任意自己想要干的活。这样一来,业务代码保持干净,横切逻辑被统一收拢到代理对象里,以后要改权限校验或者加日志,只动代理就行,压根不会碰到业务类。

这个过程说起来很抽象,但放到生活里特别好懂。明星的经纪人是典型的代理:你想找某个艺人拍广告,你不会直接去敲艺人的门,而是联系经纪人。经纪人可以做一系列事——先接需求、过滤不靠谱的合作方、谈价钱、排档期,最后才让艺人出面干活。艺人只需要专注"演广告"这件事本身,经纪约谈、档期筛选等杂事全部代理掉了。往后再换经纪公司,艺人的工作方式不变,但对接流程完全变了,这就是代理的价值。

对应到Java里,经纪人就相当于代理对象,艺人就是被代理的目标对象,广告方就是调用方。调用方持有的是经纪人这个引用,而不是艺人本人的引用。这就是理解静态代理和动态代理的出发点——代理模式的核心是解耦调用方与真实对象,在中间架设一个可控的夹层。

进入正文之前,还有一个认知要先纠正。很多人一听到"动态代理",就觉得它比静态代理高级、先进,静态代理是应该被淘汰的旧技术。这个判断其实特别片面。静态代理虽然笨拙,但它的逻辑完全显式、可控,性能开销为零,在很多场景里反而是最优解。动态代理虽然灵活,但它有自身的局限性(比如JDK动态代理只认接口),也有反射带来的性能损耗。真正的高手不是在两个方案里选一个"更好的",而是能根据场景判断"哪个更合适"。所以这篇文章我不会只讲动态代理的炫技,我会把静态代理也扎扎实实过一遍,之后你再看Spring AOP或者MyBatis源码时,会突然觉得那些代理逻辑没有那么神秘了。

2. 静态代理:最直观的代理实现,以及它为什么会"累"

2.1 一段最原始的业务代码,不掺任何代理

先从一个最基本的场景说起。假设我们有一个订单服务,接口定义如下:

public interface OrderService { void createOrder(String orderId); void cancelOrder(String orderId); }

真实实现类长这个样子:

public class OrderServiceImpl implements OrderService { @Override public void createOrder(String orderId) { System.out.println("创建订单:" + orderId); } @Override public void cancelOrder(String orderId) { System.out.println("取消订单:" + orderId); } }

业务代码写得很干净,只有一个订单状态变更的打印。但系统上线后,产品经理提了需求:所有下单和取消操作,必须有操作日志,而且要做访问权限校验。如果直接在OrderServiceImpl里加日志和校验代码,那这个业务类就同时承担了"业务逻辑"和"横切逻辑"两件事,之后的维护会变得非常痛苦。你可能觉得"就两行代码,加就加呗",但真实的业务类有几十个方法,每个方法都要加权限校验和日志,那样改一遍,代码就彻底没法看了。

这时候静态代理登场。

2.2 静态代理的经典三段式写法

静态代理实现起来非常朴素,就是手动创建一个代理类,让它实现和目标类相同的接口,同时持有目标对象的一个引用。所有接口方法里,先做自己的增强逻辑,再调用目标对象的对应方法。

public class OrderServiceStaticProxy implements OrderService { // 持有目标对象引用 private final OrderService target; public OrderServiceStaticProxy(OrderService target) { this.target = target; } @Override public void createOrder(String orderId) { System.out.println("【代理逻辑】权限校验通过,用户具备创建订单资格"); System.out.println("【代理逻辑】记录操作日志:开始创建订单 " + orderId + ",时间:" + System.currentTimeMillis()); target.createOrder(orderId); System.out.println("【代理逻辑】记录操作日志:订单 " + orderId + " 创建完成"); System.out.println("【代理逻辑】统计耗时:" + (System.currentTimeMillis() - System.currentTimeMillis()) + "ms"); } @Override public void cancelOrder(String orderId) { System.out.println("【代理逻辑】权限校验通过,用户具备取消订单资格"); target.cancelOrder(orderId); } }

调用方不再直接和OrderServiceImpl打交道,而是改为依赖这个代理类:

public class Client { public static void main(String[] args) { OrderService target = new OrderServiceImpl(); OrderService proxy = new OrderServiceStaticProxy(target); proxy.createOrder("NO_9527"); } }

这个模式的关键点就三个:

  • 代理类和目标类实现相同的接口,这样才能保证代理类可以无缝替换目标类,调用方感知不到变化。
  • 代理类持有目标类的引用,这样最终才能把请求转发给真正干活的对象。
  • 代理类在调用目标方法的前后插入增强逻辑,这就是"代理"二字的全部意义。

你发现没有,静态代理本质上就是一个"包装器"(Wrapper),它把目标对象包了一层,对外暴露的是同样的接口,但行为已经叠加了控制逻辑。调用方只看到一个接口,并不关心背后是原始对象还是代理对象,这就是面向接口编程的魅力——接口不变,实现随便换。

2.3 静态代理的致命伤:"代理爆炸"

静态代理把横切逻辑抽离出来这一点功劳必须先肯定,否则很多人会忽略它的价值。但你在上面这段代码里应该也嗅到了一个问题:我为了给OrderService加日志和权限校验,就得写一个OrderServiceStaticProxy。那如果系统里还有UserService、ProductService、CouponService呢?每个服务都需要一套类似的代理逻辑,我就得为每个接口写一个代理类。

更离谱的是,如果接口增加了新方法,比如OrderService下个月加了退款方法refundOrder,那OrderServiceImpl和OrderServiceStaticProxy得同时修改。代理类维护成本随着接口方法的增加、接口数量的增加而线性上升,最后会发展成"代理类爆炸"——你光维护代理类就维护不过来。

而且你再仔细看上面的代码,[权限校验]、[记录日志]、[统计耗时]这段增强逻辑,在UserServiceProxy里是不是几乎一模一样?静态代理不但类多,重复代码还多。你复制粘贴一次两次还可以,项目体量一大,这就是灾难。

这就是为什么我们需要动态代理——既然增强逻辑是重复的,那我能不能只写一遍这个"增强动作",然后让JVM在运行期自动为我生成代理类呢?能。JDK从1.3开始就提供了java.lang.reflect.Proxy这个动态代理机制,接下来我们看看它的庐山真面目。

3. JDK动态代理:一句话的事,背后却藏着一个精巧的机制

3.1 InvocationHandler与Proxy:跑通第一个动态代理

JDK动态代理的实现,本质上只需要两个核心元素:一个InvocationHandler接口,一个Proxy类。

InvocationHandler的官方定义是"调用处理器",它只有一个方法:

public interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

这个invoke方法有三个参数,很多人刚开始会懵。不要背,我们用语义去理解:method就是当前被调用的接口方法,args就是调用这个方法传入的参数,proxy则是一个比较特殊的存在——它代表"当前代理对象"本身。在绝大多数场景里,我们不太会使用proxy这个参数,它更多用于框架内部的一些递归判断。

我们真正的增强逻辑都写在invoke方法里,然后业务方法调用会落到这里。实现起来就是下面这个样子:

public class LogInvocationHandler implements InvocationHandler { private final Object target; public LogInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("【动态代理】方法执行前:权限校验、记录日志"); Object result = method.invoke(target, args); System.out.println("【动态代理】方法执行后:记录日志、统计耗时"); return result; } }

然后通过Proxy.newProxyInstance这个方法,动态生成代理对象:

public class JdkProxyClient { public static void main(String[] args) { OrderService target = new OrderServiceImpl(); OrderService proxy = (OrderService) Proxy.newProxyInstance( target.getClass().getClassLoader(), new Class[]{OrderService.class}, new LogInvocationHandler(target) ); proxy.createOrder("NO_9527"); proxy.cancelOrder("NO_9528"); } }

跑一下,输出结果和静态代理基本一致。这里要重点理解Proxy.newProxyInstance的三个参数:

  • ClassLoader:类加载器,用于加载动态生成的代理类。这里传target.getClass().getClassLoader()和目标类保持一致的类加载环境,可以直接用,没有特殊讲究。
  • Class<?>[] interfaces:代理类需要实现的接口列表。JDK动态代理的硬性约束就在这里——它只能为接口生成代理,不能为类生成代理。
  • InvocationHandler:调用处理器,代理对象每个方法被调用时,都会回调到它的invoke方法。

可以粗略地这样理解:你给Proxy类三样东西——用什么类加载器加载、实现哪些接口、增强逻辑长什么样(InvocationHandler),它就现场给你捏出一个代理类实例出来。静态代理是你手工写一个类文件然后编译,动态代理是让JVM在运行期帮你自动完成这个过程。

3.2 动态代理到底"动态"在哪:从编译期到运行期的质变

这里值得停下来深想一层:静态代理和动态代理的差异,表面上是一个"手写类"和"自动生成类"的差异,但本质上,是整个解决问题的时间点和空间维度发生了变化。

静态代理中,代理类和你写的业务类一样,是源代码的一部分,它经历了编译、打包、部署,是现实存在的一个Class文件。你完全可以反编译它,看到里面每一行代码。它是静态的、确定的。

而JDK动态代理中,代理类的字节码并不是预先存在的,它是在运行期由ProxyGenerator这个内部机制动态生成的。也就是说,当你执行Proxy.newProxyInstance的时候,JVM才会在内存中合成一个新的类,这个类的字节码在编译期甚至不存在于任何.java文件里。等代理类生成完毕,后续的方法调用都走这个运行时类。

打个比方。静态代理是你提前请好了一位助理,这位助理是真实的人,每天都在岗,你随时找它,它随时接活。动态代理则是你设置了一个智能客服热线——在你需要的时候,系统自动分配一个"虚拟助理"给你;你挂掉电话,这个"虚拟助理"就消失了(其实代理对象还被引用着,但类本身是在运行时生成的,没有持久化的Class文件)。

因为代理类是在运行期动态合成的,所以它天然具备一个静态代理望尘莫及的能力:同一个代理逻辑,可以为任意接口服务。不管你是OrderService还是ProductService,只要给我接口列表和InvocationHandler,我就能给你生成对应的代理对象。这解决了静态代理"每加一个接口就要写一个代理类"的痛点,堪称代理逻辑的复用革命。

3.3 为什么JDK动态代理只能代理接口

这是面试中出现频率极高、也特别能检验真实理解深度的问题。很多人只会答"JDK动态代理基于接口,CGLIB基于继承",但你要真问他一句"为什么",他就愣住。

原因其实并不神秘。JDK动态代理生成代理类时,使用的核心生成策略是ProxyGenerator,它生成的新类会直接继承java.lang.reflect.Proxy这个类。Java是单继承的,一个类只能有一个父类。既然运行期生成的代理类已经继承了Proxy,那它就不可能再继承你那个业务类了,剩下的扩展方式只有一条路——实现接口。

所以JDK动态代理不是"想"只代理接口,而是它的实现原理(继承Proxy类)决定了它只能通过接口来达成"看起来像目标类型"的效果。这个约束带来的直接后果就是:如果你的业务类没有实现任何接口,它就无法被JDK动态代理。

这也解释了为什么后来的CGLIB库要另辟蹊径——既然不能走"继承Proxy再加实现接口"这条路,那干脆用字节码生成技术直接生成一个目标类的子类,通过子类重写父类方法来实现代理。关于CGLIB,我会在下一篇专门展开,这里只需要记住一句话:JDK动态代理的"接口限制"不是设计缺陷,而是实现原理使然。

4. 底层还原:JDK动态Proxy的字节码是怎么生成和执行的

4.1 一张图之外:真实调用链路的逐步拆解

聊完了高层用法,我们往下钻一层。运行期生成代理类这句话,具体是怎么实现的?我建议你把下面这条调用链完完整整走一遍,理解之后你会觉得动态代理再也不是黑盒。

第一步,当你调用Proxy.newProxyInstance时,JDK会先检查你传入的接口列表,确认它们都是接口而不是普通类,然后调用ProxyGenerator.generateProxyClass方法,在内存中构造一个新的代理类的字节码。这个字节码虽然我们没写过,但它包含的信息非常明确:它继承Proxy,实现了你指定的OrderService接口,每个接口方法对应一个Method对象,方法体内部做的事情就是调用InvocationHandler.invoke。

第二步,这个字节码被交给类加载器去加载。类加载器加载完成之后,会得到一个Class<?>对象,这个对象的newInstance或构造函数调用,就得到了代理对象实例。

第三步,当你调用proxy.createOrder("NO_9527")时,由于代理类实现了OrderService接口,这个调用会进入代理类里名为createOrder的方法,也就是那个运行期合成的方法。这个方法的内部逻辑是:把你调用的Method对象(即OrderService.createOrder对应的Method)和参数args打包,调用内部持有的InvocationHandler.invoke方法。我们的LogInvocationHandler.invoke在这里执行增强逻辑,然后通过反射method.invoke(target, args)调用真实对象。

整条链路串起来就是:客户端调用代理对象方法 → 代理对象将调用转发给InvocationHandler.invoke → invoke方法执行增强逻辑并反射调用目标方法 → 返回结果给客户端。

我见过不少人在这儿会有一个误区:以为method.invoke(target, args)就是"代理的执行入口"。不是的,真正的入口是代理类里那个合成出来的方法,而它做的事情卑微又纯粹——把所有东西转交给InvocationHandler。所以你写增强逻辑千万别写在其他乱七八糟的地方,InvocationHandler的invoke方法就是你唯一的控制点。

4.2 实践:把运行期代理类dump出来,亲眼看看它的长相

说了这么多"合成类",到底合成出来长什么样子?与其想象,不如亲手把它抓出来看。这在调试和理解动态代理时是极其有价值的一个技巧。

在ProxyGenerator生成字节码之后、类被加载之前,JDK并没有提供公开API让你直接把字节码拿到手。但我们可以用一个小手段:在测试代码里,通过System属性或直接调用ProxyGenerator,把生成的字节码写到磁盘上。

老版本JDK(8及以前)可以直接使用ProxyGenerator.generateProxyClass:

import sun.misc.ProxyGenerator; import java.io.FileOutputStream; import java.nio.file.Files; import java.nio.file.Path; public class DumpProxyClass { public static void main(String[] args) throws Exception { byte[] classFile = ProxyGenerator.generateProxyClass( "com.example.proxy.$Proxy0", new Class[]{OrderService.class} ); Path path = Path.of("$Proxy0.class"); Files.write(path, classFile); System.out.println("已写出:" + path.toAbsolutePath()); } }

JDK 9+之后,ProxyGenerator跑到java.lang.reflect包里,同时你可以用-Djdk.proxy.ProxyGenerator.class这个隐藏参数来控制是否保留生成的类文件。这个开关在调试期非常管用,不过不同JDK版本行为略有差异,我用得最顺手的方式还是直接反射调用ProxyGenerator。

拿到$Proxy0.class之后,先用javap -p反编译一下:

javap -p -c $Proxy0.class

你会看到类似这样的结构:

final class $Proxy0 extends java.lang.reflect.Proxy implements OrderService { private static Method m1; private static Method m3; private static Method m4; public $Proxy0(InvocationHandler h) { super(h); } public final void createOrder(String orderId) throws { try { super.h.invoke(this, m3, new Object[]{orderId}); } catch (RuntimeException | Error e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } public final void cancelOrder(String orderId) throws { try { super.h.invoke(this, m4, new Object[]{orderId}); } catch (RuntimeException | Error e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } static { try { m3 = Class.forName("OrderService").getMethod("createOrder", String.class); m4 = Class.forName("OrderService").getMethod("cancelOrder", String.class); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } }

看到这个类,你心里就会彻底踏实了。原来动态代理生成的东西,本质上就是一个继承Proxy、实现业务接口、每个方法都机械地转发给InvocationHandler的类。它的静态代码块里缓存了所有接口方法的Method对象,方法调用时直接把这些Method对象交给invoke方法。所谓动态,不过是这个类在编译期不存在、运行期才会被合成出来而已。

这个dump操作,我建议每一个学动态代理的人都做一次,它比你看十篇源码分析文章都管用。一旦你知道代理类长什么样,后面遇到"为什么JDK动态代理只认接口""为什么代理对象的方法都是final"这类问题,根本不用背,看一眼字节码就全明白了。

5. 静态代理与JDK动态代理的正面交锋:到底什么时候选谁

5.1 一张对比表,讲清各自的优劣势

没有银弹。静态代理和JDK动态代理各有各的适用边界,我画了一张对比表,把平时最关心的几个维度都列清楚了:

维度静态代理JDK动态代理
代理类生成时机编译期手动编写运行期自动生成
是否需要目标类实现接口否,可直接写一个类包装任意对象是,只能基于接口生成
增强逻辑复用性差,每换一个接口基本要重写好,一个InvocationHandler通用
性能损耗零,直接方法调用有反射开销,但现代JDK已优化明显
代码可读性高,逻辑完全显式中,需要脑补代理类的存在
调试难度低,代理类就是普通类中,代理类是运行期产物,断点需要打到InvocationHandler
典型应用场景小型项目、逻辑简单、代理类数量可控框架层横切逻辑、事务/日志/权限等通用增强

这张表看着简单,但真到做技术选型时,每条都值得琢磨。举个例子,静态代理不是一无是处的古董,在代理逻辑只需要覆盖少数几个类,而且逻辑本身不太变化的时候,静态代理的直白反而是巨大优势——代码review时人人都能看懂,运行时又没有任何反射开销。我见过很多老项目里用到静态代理的地方,基本就是为了包装第三方SDK,给它的接口加一层统一的异常转换或日志输出,这种场景用动态代理反而引入不必要的复杂度。

而JDK动态代理天生适合的场景,是"增强逻辑相同、但目标对象类型五花八门"的情况,也就是典型的横切关注点:权限控制、事务管理、日志采集、性能监控。Spring AOP默认就是基于JDK动态代理,只有当目标类没有实现接口时才切换CGLIB,这正是权衡了上面所有维度后做出的选择。

5.2 动态代理常见的坑,我已经帮你踩过了

最后分享几个我在实际项目中踩过的坑,这些内容通常不会写在官方文档里,但遇到了真的很耽误时间。

第一个坑是InvocationHandler里的proxy参数没有正确理解,导致死循环或错误回调。有些人在invoke方法里对proxy调用方法,比如在"统计耗时"时又调用了proxy.createOrder,结果就是重复进入invoke,变成无限递归。记住一条原则:在handler内部永远用method.invoke(target, args)去调目标对象,不要用proxy去调,否则就递归了。

第二个坑是代理对象的类型判断。动态代理生成的$Proxy0不是OrderServiceImpl的子类,它和OrderServiceImpl唯一的联系就是实现了同一个接口。所以如果你在代码里写了proxy instanceof OrderServiceImpl这样的判断,结果会是false,这在做责任链或装饰器嵌套时会非常让人迷惑。正确做法是判断它是否实现了某接口,或者直接面向接口编程。

第三个坑是事务、连接等资源的生命周期管理。动态代理的方法转发最终落在method.invoke(target, args)这一行,如果你在invoke方法里手动开启了事务,但method.invoke抛了异常,事务的回滚代码要写在catch里,否则资源就漏了。很多线上事故就是代理层异常处理和资源释放没有配对,这个细节务必在编码时想清楚。

第四个坑比较隐蔽,是接口方法重载带来的歧义。动态代理对接口方法的重载处理还是很正常的,每种重载形式都会生成对应的Method对象,这个不用担心。真正要小心的是接口方法签名发生变化(比如增加参数)后,没有重新编译调用方,导致运行时NoSuchMethodError。这种问题在静态代理里编译期就报错了,动态代理偏不,它能正常生成Proxy类,直到真正调用时才发现Method找不着,排查起来会多花一些时间。

5.3 结尾:从"会用"到"真懂",还差一次源码阅读

如果你认真看到这里,试着问自己几个问题:为什么JDK动态代理生成的代理类方法都是final?为什么Proxy.newProxyInstance要传入接口的Class数组而不是接口实例的数组?为什么InvocationHandler的invoke方法第一个参数要传代理对象自身?

这些问题如果都能流畅作答,那恭喜你,这一篇的使命就完成了。如果你的答案还有些模糊,建议按我上面给的思路,把$Proxy0的字节码dump出来自己看一遍,再顺手翻一下Proxy类的源码。我一直认为,动态代理这种技术,只有当你亲手把运行期的类抓出来看清楚了,它才算真正变成你自己的东西。

这一篇我重点讲了静态代理和JDK动态代理,尤其是JDK动态代理的底层生成机制。但代理的大戏还远没结束:CGLIB怎么通过继承实现代理?为什么Spring AOP在目标类没有接口时会选择CGLIB?JDK动态代理和CGLIB在性能上到底差多少?还有代理对象的toString、hashCode、equals为什么也要经过InvocationHandler?这些内容我都放在了下一篇。下一篇我们会把CGLIB的源码和Spring AOP的选择逻辑一起拆开讲,看完之后,你对代理的理解就能真正连成一张完整的网了。

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

Direct3D渲染流水线精要:从初始化到三角形绘制实战

1. 为什么要先搞懂渲染流水线&#xff0c;再动手写Direct3D很多人学Direct3D时&#xff0c;习惯性地从“怎么创建窗口”开始&#xff0c;然后照着教程敲一遍CreateDevice、CreateRenderTargetView&#xff0c;跑出一个蓝色清屏就觉得自己入门了。但一旦要画三角形、画模型&…

作者头像 李华
网站建设 2026/10/9 4:15:31

Java匿名内部类全面解析:语法本质、变量捕获与内存泄漏

面试时我常问应聘者一个问题&#xff1a;你用过匿名内部类吗&#xff1f;十个里有九个说用过&#xff0c;写到new Thread(new Runnable(){...})的时候个个手速飞快。但等我追问一句&#xff1a;“这个匿名内部类的实例&#xff0c;在 JVM 里到底是一个什么东西&#xff1f;它凭…

作者头像 李华
网站建设 2026/10/9 4:15:02

光纤熔接实操全解:从设备选型到OTDR验收的综合布线指南

简介&#xff1a;这份《综合布线-光纤熔接步骤介绍》PPT面向网络工程、智能建筑及弱电施工人员&#xff0c;系统讲解综合布线系统&#xff08;SCS&#xff09;的概念、特点与应用场景&#xff0c;并重点拆解光纤熔接的关键操作流程。内容涵盖兼容性、开放性、灵活性、可靠性、先…

作者头像 李华
网站建设 2026/10/9 4:13:55

SpringBoot项目“找不到或无法加载主类”原因与修复排查指南

这两天后台收到的消息里&#xff0c;有一半都是同一个问题&#xff1a;SpringBoot项目一启动就报“错误: 找不到或无法加载主类”。有人在IDEA里直接点运行跑崩了&#xff0c;有人是java -jar启动打好的jar包失败&#xff0c;还有的在Eclipse里连Tomcat都没拉起来就退出了。这个…

作者头像 李华
网站建设 2026/10/9 4:13:50

神经PDE求解器中的奇异性与边界极限建模

1. 项目概述&#xff1a;当神经网络撞上偏微分方程的“边界条件”你有没有试过用深度学习模型去解一个物理场问题——比如热传导、流体速度分布&#xff0c;或者电磁波在复杂介质里的传播&#xff1f;我去年接手一个工业仿真加速项目&#xff0c;客户希望把传统有限元求解器的单…

作者头像 李华
网站建设 2026/10/9 4:13:50

SAFE-MR:多模态谣言检测中的证据充分性评估框架

1. 项目概述&#xff1a;当谣言检测遇上“选择性信任”——SAFE-MR到底在解决什么问题&#xff1f;你有没有遇到过这样的场景&#xff1a;一条带图的微博说“某地突发地震&#xff0c;已造成百人伤亡”&#xff0c;配图是摇晃的楼体和惊慌的人群&#xff1b;另一条微信公众号推…

作者头像 李华