Java 面试题:Java 的动态代理是基于什么原理?
编程语言通常有各种不同的分类角度,动态类型和静态类型就是其中一种分类角度,简单区分就是语言类型信息是在运行时检查,还是编译期检查。
与其近似的还有一个对比,就是所谓强类型和弱类型,就是不同类型变量赋值时,是否需要显式地(强制)进行类型转换。那么,如何分类 Java 语言呢?
通常认为,Java 是静态的强类型语言,但是因为提供了类似反射等机制,也具备了部分动态类型语言的能力。
文章目录
- 1、面试问题
- 2、问题分析
- 3、典型回答
- 4、问题深入
- 5、问题拓展
- 5.1、问题拓展:解释`InvocationHandler`和`Proxy`类的内部工作机制;
- 5.1.1、`Proxy` 类
- 5.1.2、`InvocationHandler` 接口
- 5.1.3、工作机制
- 5.2、问题拓展:论 Java 反射机制在动态代理中的作用及其性能影响以及及如何减少这些开销;
- 5.2.1、反射在动态代理中的作用
- 5.2.2、性能影响
- 5.2.3、性能优化策略
- 5.3、问题拓展:讨比较JDK动态代理与其他代理技术(如CGLIB)在性能方面的差异。
- 5.3.1、JDK 动态代理
- 5.3.2、CGLib
- 5.3.3、性能比较
- 5.3.4、应用场景
- 5.4、问题拓展:讨论动态代理在实际开发中的具体应用,如在哪些场景下是不可替代的
- 5.4.1、AOP(面向切面编程)
- 5.4.2、事务管理
- 5.4.3、远程方法调用(RMI)
- 5.4.4、资源管理
- 5.4.5、接口兼容性和适配器
- 5.4.6、延迟加载
- 5.4.7、安全访问控制
- 5.5、问题拓展;探讨如何使用动态代理进行错误处理和异常管理
- 5.5.1、实现动态代理的异常管理
- 5.5.2、动态代理的异常处理优势
1、面试问题
今天的面试问题:Java 的动态代理是基于什么原理?
2、问题分析
这个面试题主要考察了以下几个关键点:
- 反射机制的理解:这个问题测试你是否了解 Java 中反射机制的基本概念,特别是如何在运行时动态创建代理类和对象。反射是动态代理实现的核心,允许程序在运行时查询对象的属性和调用对象的方法;
- 接口和代理设计模式的应用:通过动态代理的问题,面试官希望看到你是否理解代理设计模式的基本原理以及如何通过接口将代理类与实际执行类解耦,增强功能或进行访问控制;
- 适用场景的理解:面试官通过这个问题可能会进一步探讨你对动态代理应用场景的理解,比如在哪些情况下使用动态代理,它在 AOP(面向切面编程)、事务管理、日志记录等方面的应用。
- Java API 的熟悉程度:了解
java.lang.reflect.Proxy和 ;java.lang.reflect.InvocationHandler等关键类的使用方法和特性,显示出你对 Java API 的掌握程度。这是评估 Java 开发者技能的一个重要方面。
总体来说,这个问题不仅考察了技术细节,还考察了面试者在面对设计模式和架构选择时的决策能力。理解和应用动态代理可以帮助开发者在需要时实现代码的解耦和功能增强,是高级 Java 开发者的标志性技能之一。
3、典型回答
首先,Java 的动态代理是基于反射机制实现的高级功能,它允许我们在运行时动态创建代理类和对象,来代理实际对象,进行方法调用的中介处理。这一机制通过 Java 核心的反射 API 中的 Proxy 类和 InvocationHandler 接口实现。
其中实现的具体过程是:通过一个类加载器、一组接口及一个调用处理器作为输入参数,利用Proxy类的 newProxyInstance 方法在内存中动态创建一个实现指定接口的代理对象。该代理对象会将所有方法调用转发到实现了 InvocationHandler 接口的调用处理器的 invoke 方法中。
在 invoke 方法里,可以自定义方法调用前后的操作,如日志记录、权限检查和事务处理等。这使得动态代理不仅增强了程序的灵活性,而且有助于业务逻辑与系统服务的解耦。
此外,除了 JDK 内置的动态代理实现,还可以使用字节码操作技术如 ASM、CGLIB(基于ASM)和Javassist 等。这些技术提供了更底层的操作能力,比如允许直接针对类而非仅限于接口创建代理,适用于性能要求更高或需求更复杂的系统。
4、问题深入
如果继续深入,面试官可以从各种不同的角度考察,比如可以:
- 原理的深入理解,比如:①、解释
InvocationHandler和Proxy类的内部工作机制;②、讨论 Java 反射机制在动态代理中的作用及其性能影响; - 性能优化,比如:①、讨论动态代理的性能开销及如何减少这些开销;②、讨比较JDK动态代理与其他代理技术(如CGLIB)在性能方面的差异。
- 实际应用场景,比如:①、讨论动态代理在实际开发中的具体应用,如在哪些场景下是不可替代的;②、探讨如何使用动态代理进行错误处理和异常管理。
5、问题拓展
5.1、问题拓展:解释InvocationHandler和Proxy类的内部工作机制;
Java 的 InvocationHandler 和 Proxy 类是实现动态代理的关键组件,广泛应用于运行时动态创建代理类的情况,如远程方法调用、事务管理、日志记录等。这种机制主要依赖 Java 反射 API,使得开发者能够在运行时动态处理方法调用。
5.1.1、Proxy 类
Proxy 类提供了用于创建动态代理实例的静态方法。动态代理类是在运行时生成的类,它实现了指定的一组接口。
-
创建动态代理实例
:最常用的方法是
Proxy.newProxyInstance(),这个方法需要三个参数:
- 类加载器(
ClassLoader):用来定义代理类的类加载器。 - 接口数组(
Class[]):这是一个接口数组,代理类将实现这些接口。 InvocationHandler实现:当代理实例的方法被调用时,将会调用此处理器的invoke()方法。
- 类加载器(
5.1.2、InvocationHandler 接口
InvocationHandler 是一个接口,开发者需要实现它的 invoke() 方法来定义代理实例的行为。
-
invoke()方法:这个方法有三个参数:
- 代理实例(
proxy):调用该方法的代理实例。 - 方法对象(
Method):对应于在代理实例上调用的接口方法的Method实例。 - 参数数组(
args):调用接口方法时传递的参数。
- 代理实例(
5.1.3、工作机制
当代理实例的方法被调用时,调用将被重定向到 InvocationHandler 的 invoke() 方法。invoke() 方法可以根据需要进行增强处理,如日志记录、事务处理、延迟加载等,然后可能通过反射调用实际对象的相应方法。
例如,如果你有一个接口 MyInterface 和实现该接口的类 MyImpl,你可以创建一个 InvocationHandler,在调用任何 MyInterface 的方法之前和之后执行特定操作。创建动态代理后,任何对 MyInterface 方法的调用都会转发给 InvocationHandler。
示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;interface MyInterface {void doSomething();
}class MyImpl implements MyInterface {public void doSomething() {System.out.println("Doing something...");}
}class MyInvocationHandler implements InvocationHandler {private final MyInterface original;public MyInvocationHandler(MyInterface original) {this.original = original;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method call");Object result = method.invoke(original, args); // 调用实际对象的方法System.out.println("After method call");return result;}
}public class ProxyExample {public static void main(String[] args) {MyInterface original = new MyImpl();MyInterface proxy = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(),new Class<?>[] {MyInterface.class},new MyInvocationHandler(original));proxy.doSomething(); // 调用代理的方法,这将触发 MyInvocationHandler 的 invoke 方法}
}
这个例子中:
MyInterface是一个接口,MyImpl是这个接口的一个具体实现;MyInvocationHandler实现了InvocationHandler接口,用于定义在调用方法前后要执行的操作;- 使用
Proxy.newProxyInstance()创建了一个MyInterface的代理实例。当调用proxy.doSomething()时,实际上会通过MyInvocationHandler的invoke()方法进行调用。
5.2、问题拓展:论 Java 反射机制在动态代理中的作用及其性能影响以及及如何减少这些开销;
Java 反射机制在动态代理中的作用是核心的,但同时也会对性能产生一定的影响。下面将详细讨论这两个方面:
5.2.1、反射在动态代理中的作用
-
接口方法的动态调用:反射允许动态代理在运行时查找并调用方法。当代理类的一个方法被调用时,
InvocationHandler的invoke方法就会被触发,这个方法利用反射来决定哪一个方法应该被调用,以及如何传递参数。 -
无需硬编码:使用反射,开发者无需在编写代码时就确定要调用哪些类和方法。这使得代码更加灵活和可扩展,因为可以在运行时动态加载和调用类和方法。
-
适用性广泛:反射使得动态代理不仅可以用于实现已知的接口,还可以动态地应对程序扩展中新增的接口,提高了代码的复用性和模块间的解耦能力。
5.2.2、性能影响
尽管反射在动态代理中提供了极大的灵活性和强大的功能,它也有一些性能上的不足:
-
性能开销:反射操作本质上比直接方法调用更慢。这是因为反射涉及到类型检查和方法调用解析等额外的处理步骤。每次通过反射调用方法时,JVM 都需要检查方法的访问权限,并且在调用前将参数类型匹配到方法的参数类型;
-
内存消耗:使用反射的动态代理可能会额外消耗更多内存,因为 JVM 需要为被代理的方法以及相关的数据结构(如
Method对象)分配内存; -
优化限制:使用反射调用方法通常不能享受到 JIT 编译器的一些优化,如内联展开等,这进一步影响了性能。
5.2.3、性能优化策略
尽管反射带来了性能挑战,但可以采取一些措施来缓解这些问题:
- 缓存反射对象:可以缓存关键的反射对象(如
Method实例),以减少查找和创建这些对象的开销; - 限制代理类数量:避免过度使用动态代理,特别是在性能敏感的应用场景中,因为每一个代理类都会增加额外的运行时开销;
- 使用第三方库:例如 CGLib 或 ByteBuddy 等库可以通过生成字节码来创建代理,而不是使用 Java 原生的反射,这样可以提高性能。
总之,虽然反射和动态代理提供了极大的灵活性和强大的功能,但在使用时需要权衡其带来的性能开销。在设计系统时,合理选择使用动态代理的场景,并采取适当的优化措施,是提高系统性能的关键。
5.3、问题拓展:讨比较JDK动态代理与其他代理技术(如CGLIB)在性能方面的差异。
在 Java 中,动态代理主要有两种常见的实现方式:JDK 动态代理和第三方库,如 CGLib。这两种技术在性能和适用性方面都有各自的特点和差异。
5.3.1、JDK 动态代理
JDK 动态代理使用 Java 自带的代理类库来实现,它依赖于反射(java.lang.reflect 包)和接口:
- 基于接口:JDK 动态代理只能代理接口,不支持类。这意味着只有实现了接口的类才可以被代理;
- 性能影响:由于 JDK 代理基于反射实现,其性能通常不如直接方法调用。尽管 Java 的反射性能在近年有所改进,但反射调用仍然比直接调用慢;
- 内存和加载时间:JDK 代理的加载时间相对较短,内存消耗较少,因为它只需要生成实现指定接口的代理类。
5.3.2、CGLib
CGLib(Code Generation Library)是一个强大的、高性能的代码生成库,它使用字节码增强技术(通过继承类)来实现代理,而不仅仅是基于接口:
- 基于类的代理:CGLib 可以代理没有实现接口的类,因此它比 JDK 动态代理更为灵活;
- 性能优势:CGLib 在运行时生成的是具体类的子类,并覆盖其中的方法。相比于 JDK 的反射机制,CGLib 通常能提供更好的性能,因为它直接操作字节码,避免了反射调用的开销;
- 内存和加载时间:CGLib 生成的代理类比 JDK 代理更复杂,可能会导致更长的加载时间和更高的内存消耗。此外,CGLib 在生成代理类时需要处理更多的字节码操作,这在初次加载时可能导致性能开销。
5.3.3、性能比较
- 调用速度:CGLib 代理的方法调用通常比 JDK 代理快,因为它避免了使用反射。CGLib 直接修改字节码,减少了调用时的计算量;
- 启动速度:JDK 动态代理在生成代理类时较快,因为它仅涉及到简单的接口实现。而 CGLib 在启动时可能需要更多时间来生成字节码;
- 资源消耗:CGLib 由于在运行时创建较复杂的类,可能会消耗更多内存。JDK 动态代理则相对节省资源。
5.3.4、应用场景
如果你的类已经实现了接口,或者你只需要代理接口方法,JDK 动态代理是一个简单而高效的选择;
如果你需要代理没有实现接口的类,或者追求最佳性能,CGLib 是更好的选择。
总的来说,选择哪种代理技术取决于具体需求、性能考量和代理对象的特点。在不需要处理接口的情况下,CGLib 的性能优势通常会使它成为更受欢迎的选择。
5.4、问题拓展:讨论动态代理在实际开发中的具体应用,如在哪些场景下是不可替代的
动态代理在实际开发中扮演了非常重要的角色,尤其是在需要增强或修改原有类行为而不改变原有代码的情况下。以下是一些具体的应用场景,展示了动态代理的价值和不可替代性:
5.4.1、AOP(面向切面编程)
AOP 是动态代理应用最广泛的领域之一,尤其在如 Spring 框架中。通过动态代理,可以在不修改原有代码的基础上,为方法调用提供横切关注点(如日志记录、事务管理、安全检查等)的处理。这种方式使得关注点分离,增强了代码的可维护性和复用性。
5.4.2、事务管理
在企业应用中,事务管理是必不可少的功能,特别是在数据库操作中。通过使用动态代理,可以自动地为业务方法调用加入事务处理逻辑,如开启事务、提交或回滚事务。这样做可以避免将事务管理代码硬编码到业务逻辑中,提高代码的清晰性和可维护性。
5.4.3、远程方法调用(RMI)
动态代理常用于实现远程方法调用的客户端逻辑。在 Java RMI 或其他远程调用框架如 Spring 的 Remoting 中,客户端可以通过动态代理透明地调用远程服务。代理对象负责将本地接口调用转换为网络请求,并处理来自服务端的响应,对用户来说,远程调用与本地调用无异。
5.4.4、资源管理
动态代理可以用于智能资源管理,如数据库连接和线程池的管理。代理可以控制资源的分配和释放,确保例如数据库连接始终在使用完毕后被正确关闭,从而避免资源泄露。
5.4.5、接口兼容性和适配器
在需要适配旧版本接口到新的实现时,动态代理可以充当适配器的角色,无需修改现有代码。这种方式非常适合在升级和维护大型遗留系统时,为旧接口提供新的实现。
5.4.6、延迟加载
动态代理可以用于实现延迟加载(懒加载),特别是在处理大型对象或复杂对象关系时。例如,代理可以控制只有在实际需要时才加载对象的某些部分,从而减少系统的初始化时间和运行时的内存消耗。
5.4.7、安全访问控制
动态代理还可以用于增强安全性,通过代理控制对敏感方法的访问。代理可以在方法执行前进行安全检查,如验证用户权限,确保只有具备相应权限的用户才能执行某些操作。
这些应用场景展示了动态代理在解耦、增强方法、处理交叉关注点等方面的巨大优势。在现代软件开发中,动态代理技术是实现中间件、框架和各种库的一个不可或缺的工具,它提供了一种强大且灵活的方法来动态修改和增强对象的行为。
5.5、问题拓展;探讨如何使用动态代理进行错误处理和异常管理
使用动态代理进行错误处理和异常管理是一种增强应用程序健壮性的有效技术。通过动态代理,开发者可以在不修改原有业务逻辑代码的情况下,集中处理方法调用过程中可能发生的异常。这种模式在企业级应用中非常常见,特别是在需要统一异常处理逻辑的系统中。
5.5.1、实现动态代理的异常管理
动态代理允许开发者在一个集中的位置拦截方法调用,并在这个层面上实施异常处理策略。以下是实现此功能的基本步骤:
-
定义业务接口:首先定义一个或多个业务逻辑接口,这些接口包含了应用程序中需要执行的方法;
-
实现业务逻辑:实现这些接口,编写具体的业务逻辑;
-
创建动态代理:使用 JDK 动态代理或第三方库(如 CGLib),创建一个代理类,该类在内部使用
InvocationHandler; -
编写
InvocationHandler实现:在InvocationHandler的invoke方法中,实现异常捕获和处理逻辑。这允许你在方法执行前后添加额外的处理,比如异常日志记录、异常转换、重试逻辑等; -
使用代理实例:在应用程序中,使用动态代理实例代替原始业务对象。所有对原始对象的方法调用都会通过代理,并由代理中的异常处理逻辑处理。
示例代码:
以下是使用 JDK 动态代理进行异常管理的简单示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;interface Service {void process() throws Exception;
}class ServiceImpl implements Service {public void process() throws Exception {// 模拟业务逻辑System.out.println("Processing service");throw new Exception("Something went wrong!");}
}class ExceptionHandlingInvocationHandler implements InvocationHandler {private Object target;public ExceptionHandlingInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {return method.invoke(target, args);} catch (Exception e) {handleException(e);return null; // 根据具体需求返回适当的值或抛出自定义异常}}private void handleException(Exception e) {// 统一异常处理逻辑System.out.println("Handled exception: " + e.getMessage());}
}public class ProxyExample {public static void main(String[] args) {Service realService = new ServiceImpl();Service proxyService = (Service) Proxy.newProxyInstance(Service.class.getClassLoader(),new Class<?>[]{Service.class},new ExceptionHandlingInvocationHandler(realService));try {proxyService.process();} catch (Exception e) {System.out.println("Exception: " + e.getMessage());}}
}
5.5.2、动态代理的异常处理优势
- 集中管理:可以在一个地方集中管理所有异常处理逻辑,提高代码的可维护性;
- 解耦:将异常处理逻辑从业务代码中解耦,使业务逻辑更加清晰;
- 灵活性:可以灵活地添加或修改异常处理策略而不需要修改业务逻辑代码;
- 重用性:相同的异常处理逻辑可以应用到多个服务或组件上。
动态代理提供了一种强大的方式来增强方法调用,包括统一的异常处理,这在构建大型、复杂的系统时尤为重要。
相关文章:
Java 面试题:Java 的动态代理是基于什么原理?
编程语言通常有各种不同的分类角度,动态类型和静态类型就是其中一种分类角度,简单区分就是语言类型信息是在运行时检查,还是编译期检查。 与其近似的还有一个对比,就是所谓强类型和弱类型,就是不同类型变量赋值时&…...
Python logging 模块详解
Python 的 logging 模块提供了一个强大而灵活的日志系统。它是 Python 标准库的一部分,因此可以在任何 Python 程序中使用。logging 模块提供了许多有用的功能,包括日志消息的级别设置、日志消息的格式设置、将日志消息输出到不同的目标,以及…...
http://account.battlenet.com.cn
http://account.battlenet.com.cn 魔兽战网 短信验证 查了下,我老早以前账号还在,纪念下,少玩游戏。...
java第二十课 —— 面向对象习题
类与对象练习题 编写类 A01,定义方法 max,实现求某个 double 数组的最大值,并返回。 public class Chapter7{public static void main(String[] args){A01 m new A01();double[] doubleArray null;Double res m.max(doubleArray);if(res !…...
Flask的模块化实践
既作为前端,又作为后端的我,写flask写了那么多行了,其实它们属于不同的模块,比如登录,注册,聊天,用户画像,那我觉得有必要分一下了,系统化的处理一下,不然找个…...
锁存器(Latch)的产生与特点
Latch 是什么 Latch 其实就是锁存器,是一种在异步电路系统中,对输入信号电平敏感的单元,用来存储信息。锁存器在数据未锁存时,输出端的信号随输入信号变化,就像信号通过一个缓冲器,一旦锁存信号有效&#…...
搜维尔科技:「案例」Faceware电影中面部动画的演变历程
面部动画是电影中角色表演的一个重要方面,尤其是在严重依赖电子动画、化妆效果和动作捕捉系统的奇幻电影中。在《龙与地下城:盗贼荣誉》电影中,龙裔角色的面部动画是一个复杂的系统,使该生物在大屏幕上栩栩如生。该系统依赖于一种…...
特征工程技巧—Bert
前段时间在参加比赛,发现有一些比赛上公开的代码,其中的数据预处理步骤值得我们参考。 平常我们见到的都是数据预处理,现在我们来讲一下特征工程跟数据预处理的区别。 数据预处理是指对原始数据进行清洗、转换、缩放等操作,以便为…...
更改 Docker 的默认存储位置
记录一下使用 Docker 遇到的问题,Docker 也用得比较多,最近发现根目录所在磁盘快满了,发现是 Docker 默认会将镜像和容器等数据保存在目录 /var/lib/docker 目录下,我们可以更改 Docker 的默认存储位置,比如改到数据盘…...
搜索与图论:图中点的层次
搜索与图论:图中点的层次 题目描述参考代码 题目描述 输入样例 4 5 1 2 2 3 3 4 1 3 1 4输出样例 1参考代码 #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 100010;int n, m; int h[N], e[N]…...
NLP入门——数据预处理:编码规范化
编码规范化 在计算机中,我们需要将字符与字节序列之间建立起映射关系,这个过程被称为编码。有许多不同的编码方式,例如 ASCII、UTF-8、UTF-16 和 GBK 等。这些编码方式会将每个字符编码为一个或多个字节,以便于在计算机、网络和其…...
代码随想录算法训练营第四十八天| 70. 爬楼梯 (进阶)、322. 零钱兑换、279.完全平方数
70. 爬楼梯 (进阶) 题目链接:70. 爬楼梯 (进阶) 文档讲解:代码随想录/爬楼梯 (进阶) 状态:已完成(0遍) 解题过程 这几天博主忙着面试和入职&am…...
c++11 constexpr关键字
constexpr 是 C11 引入的一个关键字,它允许在编译时计算表达式的值,并将这些值存储在程序的常量部分中。这意味着 constexpr 变量和函数可以在编译时进行求值,从而避免了运行时的开销。 constexpr变量 constexpr 变量必须在编译时初始化&am…...
ios 获取图片的一部分区域
可以使用如下的代码: // get part of the image - (UIImage *)getPartOfImage:(UIImage *)img rect:(CGRect)partRect {CGImageRef imageRef img.CGImage;CGImageRef imagePartRef CGImageCreateWithImageInRect(imageRef, partRect);UIImage *retImg [UIImage i…...
数据结构(3)栈、队列、数组
1 栈 1.1 栈的定义 后进先出【LIFO】 1.2 基本操作 元素进栈出栈 只能在栈顶进行!!! 经常考的题: 穿插的进行进栈和出栈 可能有多个选项 1.3 顺序栈 1.3.1 初始化 下标是从0开始的 1.3.2 进栈 更简单的写法: 1.3…...
数据库(入门)
文章目录 一、数据库(DB) 二、数据库管理系统(DBMS) 三、SQL(结构化查询语言) 四、三者的关系 五、端口号(port number) 一、数据库(DB) 定义:按照一定格式存储数据的一些文件的组合。 简单来…...
ChatTTS+Python编程搞定语音报时小程序
文字转语音神器Python编程搞定语音报时小程序 今天一个好哥们发了一个文字转语音的AI神器的短视频。这个神器的网站是[ChatTTS - Text-to-Speech for Conversational Scenarios][https://chattts.com/],如下图所示: 这个开源项目可以从github.com上下载…...
【Mac】Alfred 5 for Mac(苹果效率提升工具)v5.5软件介绍及安装教程
软件介绍 Alfred 是适用于 Mac 操作系统的流行生产力应用程序。它旨在帮助用户在 Mac 电脑上更高效地启动应用程序、搜索文件和文件夹以及执行各种任务。借助 Alfred,用户可以创建自定义键盘快捷方式、设置自定义工作流程并使用热键访问功能。 Alfred for Mac 的一…...
PDF文件处理不再复杂:9个Python库让一切变得简单
大家好,这里是程序员晚枫,2年前发布了一个开源项目:python-office,目前在GitHub上有800⭐,最近在开发新功能时感觉Python知识有点不够用了。 所以打算从2方面补充自己的知识:研究优秀的第三方库和学习Pyth…...
安防视频融合汇聚平台EasyCVR如何实现视频画面自定义标签?
安防视频融合汇聚平台EasyCVR兼容性强,可支持Windows系统、Linux系统以及国产化操作系统等,平台既具备传统安防视频监控的能力,也具备接入AI智能分析的能力,可拓展性强、视频能力灵活,能对外分发RTMP、RTSP、HTTP-FLV、…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
