当前位置: 首页 > news >正文

湖州佳成建设网站/媒介星软文平台

湖州佳成建设网站,媒介星软文平台,个人网站想添加支付功能怎么做,网站建设目标怎么看文章目录一、动手实现一个动态代理框架1、初识javassist2、使用javassist实现一个动态代理框架二、JDK动态代理1、编码实现2、基本原理(1)getProxyClass0方法(2)总结写在后面一、动手实现一个动态代理框架 1、初识javassist Jav…

文章目录

  • 一、动手实现一个动态代理框架
    • 1、初识javassist
    • 2、使用javassist实现一个动态代理框架
  • 二、JDK动态代理
    • 1、编码实现
    • 2、基本原理
      • (1)getProxyClass0方法
      • (2)总结
  • 写在后面

一、动手实现一个动态代理框架

1、初识javassist

Java操纵字节码,最底层一般是使用ASM进行操作的,但是ASM上手难度很大,我们可以使用javassist对字节码进行操作,相对来说简单一些。

下面这个实例,就是我们使用javassist对接口动态生成一个实现类:


import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;public class JavassistDemo {public static void main(String[] args) throws Exception {TestService proxy = createProxy();proxy.sayHello("zhangsan"); // hello:zhangsan}/*** 生成一个TestService的实现类*/public static TestService createProxy() throws Exception {// javassist 底层是ASM,ASM底层是编辑JVM指令码ClassPool classPool = new ClassPool();// 添加classLoaderclassPool.appendSystemPath();// 1.创建一个类CtClass class1 = classPool.makeClass("TestServiceImpl");class1.addInterface(classPool.get(TestService.class.getName()));// 2.创建一个方法CtMethod satHelloMethod = CtNewMethod.make(CtClass.voidType, // void返回值"sayHello", // 方法名new CtClass[]{classPool.get(String.class.getName())}, // 方法参数new CtClass[0], // 异常类型"{System.out.println(\"hello:\"+$1);}", // 方法体内容,$1表示第一个参数class1 // 指定类);class1.addMethod(satHelloMethod);// 3.实例化这个对象Class aClass = classPool.toClass(class1);// 强制转换return (TestService) aClass.newInstance();}public interface TestService {void sayHello(String name);}
}

2、使用javassist实现一个动态代理框架


import javassist.*;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;public class Javassist3Demo {public static void main(String[] args) throws Exception {TestService proxy = createProxy(TestService.class, new InvocationHandler() {@Overridepublic Object invoke(String methodName, Object[] args) {// 根据方法判断逻辑if(methodName.equals("sayHello3")) {System.out.println("hello" + args[0]);return "aa";} else {System.out.println("hello2" + args[0]);return "aa2";}}});proxy.sayHello("zhangsan"); // hellozhangsanproxy.sayHello2("zz", 1);System.out.println(proxy.sayHello3("qq"));}static int count = 0;public static <T> T createProxy(Class<T> classInterface, InvocationHandler handler) throws Exception {ClassPool classPool = new ClassPool();classPool.appendSystemPath();// 1.创建一个类CtClass impl = classPool.makeClass("$Proxy" + count ++);impl.addInterface(classPool.get(classInterface.getName()));// 2.impl类中 添加属性handlerCtField fie = CtField.make("public com.mydemo.Javassast3Demo.InvocationHandler handler=null;", impl);impl.addField(fie);// 有返回值类型和无返回值类型的源码String src = "return ($r)this.handler.invoke(\"%s\", $args);"; // $args获取所有参数String voidSrc = "this.handler.invoke(\"%s\",$args);";for (Method method : classInterface.getMethods()) {CtClass returnType = classPool.get(method.getReturnType().getName());String name = method.getName();CtClass[] parameters = toCtClass(classPool, method.getParameterTypes());CtClass[] errors = toCtClass(classPool, method.getExceptionTypes());// 2.创建一个方法CtMethod newMethod = CtNewMethod.make(returnType, // 返回值name, // 方法名parameters, // 方法参数errors, // 异常类型method.getReturnType().equals(Void.class) ? String.format(voidSrc, method.getName()) : String.format(src, method.getName()), // 方法体内容impl // 指定类);impl.addMethod(newMethod);}// 生成字节码(辅助学习用)//byte[] bytes = impl.toBytecode();//Files.write(Paths.get(System.getProperty("user.dir") + "/target/" + impl.getName() + ".class"), bytes);// 3.实例化这个对象Class aClass = classPool.toClass(impl);T t = (T) aClass.newInstance();aClass.getField("handler").set(t, handler); // 初始化赋值// 强制转换return t;}private static CtClass[] toCtClass(ClassPool pool, Class[] classes) {return Arrays.stream(classes).map(c -> {try {return pool.get(c.getName());} catch (NotFoundException e) {throw new RuntimeException(e);}}).collect(Collectors.toList()).toArray(new CtClass[0]);}public interface InvocationHandler {Object invoke(String methodName, Object args[]);}public class InvocationHandlerImpl implements InvocationHandler {@Overridepublic Object invoke(String methodName, Object[] args) {System.out.println("hello");return null;}}public interface TestService {void sayHello(String name);void sayHello2(String name, Integer id);String sayHello3(String name);}
}

这样,我们只要实现InvocationHandler 接口,就可以自定义代理类的核心逻辑了,我们对生成的代理类进行反编译:

public class $Proxy0 implements TestService {public InvocationHandler handler = null;public String sayHello3(String var1) {return (String)this.handler.invoke("sayHello3", new Object[]{var1});}public void sayHello(String var1) {this.handler.invoke("sayHello", new Object[]{var1});}public void sayHello2(String var1, Integer var2) {this.handler.invoke("sayHello2", new Object[]{var1, var2});}public $Proxy0() {}
}

实现了我们的接口,并且重写了接口的所有方法,最终执行的是InvocationHandler的invoke方法。

这也正是JDK动态代理的基本思想。

二、JDK动态代理

1、编码实现

public interface EchoService {String echo(String message) throws NullPointerException;
}public class DefaultEchoService implements EchoService {@Overridepublic String echo(String message) {return "[ECHO] " + message;}
}import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** JDK动态代理实例*/
public class JDKDynamicProxyDemo {public static void main(String[] args) {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();// 真实的对象DefaultEchoService realObj = new DefaultEchoService();// 代理的对象Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态前置");Object obj = null;if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {// 执行真实方法obj = method.invoke(realObj, args);}System.out.println("动态后置");return obj;}});EchoService echoService = (EchoService) proxy;System.out.println(echoService.echo("Hello,World"));}
}

我们发现,使用JDK动态代理,基本逻辑和我们上面使用javassist手写的工具类差不多,只不过JDK动态代理底层是使用更复杂的方式实现的,我们这里取巧,使用javassist实现。

注意!这里需要DefaultEchoService 实现EchoService接口,代理的其实是EchoService接口而不是DefaultEchoService 类。

动态代理对原代码没有侵入性,通常可以动态加载。

2、基本原理

为什么 Proxy.newProxyInstance 会生成新的字节码?

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;}
});System.out.println(proxy.getClass());// com.sun.proxy.$Proxy0Object proxy2 = Proxy.newProxyInstance(classLoader, new Class[]{Comparable.class}, (proxy1, method, args1) -> {return null;});System.out.println(proxy2.getClass());// com.sun.proxy.$Proxy1

上面代码我们会发现,Java动态代理每生成一个代理,它的class总是com.sun.proxy包下的$Proxy*,从0开始累加,它是如何实现的呢?

我们来分析一下Proxy的newProxyInstance方法:

// java.lang.reflect.Proxy#newProxyInstance
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
{Objects.requireNonNull(h);// 对象克隆final Class<?>[] intfs = interfaces.clone();final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** Look up or generate the designated proxy class.*/// 先从缓存获取(见 (1))Class<?> cl = getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}// 获取代理对象的构造方法,带着InvocationHandler参数的构造方法final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}// 返回Proxy对象return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}
}

(1)getProxyClass0方法

在getProxyClass0方法中,从proxyClassCache缓存中获取了这个代理类:

// java.lang.reflect.Proxy#getProxyClass0
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);
}

而proxyClassCache在初始化时,自动创建了KeyFactory和ProxyClassFactory

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

ProxyClassFactory的核心方法apply,隐藏着代理接口的创建逻辑:

// java.lang.reflect.Proxy.ProxyClassFactory
private static final class ProxyClassFactoryimplements BiFunction<ClassLoader, Class<?>[], Class<?>>
{// prefix for all proxy class namesprivate static final String proxyClassNamePrefix = "$Proxy";// next number to use for generation of unique proxy class namesprivate static final AtomicLong nextUniqueNumber = new AtomicLong();@Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);for (Class<?> intf : interfaces) { // 遍历我们传入的接口数组/** Verify that the class loader resolves the name of this* interface to the same Class object.*/Class<?> interfaceClass = null;try {// 通过classLoader加载我们的接口interfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {throw new IllegalArgumentException(intf + " is not visible from class loader");}/** Verify that the Class object actually represents an* interface.*/if (!interfaceClass.isInterface()) {// 只能代理接口,非接口直接抛异常throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}/** Verify that this interface is not a duplicate.*/if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}}String proxyPkg = null;     // package to define proxy class inint accessFlags = Modifier.PUBLIC | Modifier.FINAL;/** Record the package of a non-public proxy interface so that the* proxy class will be defined in the same package.  Verify that* all non-public proxy interfaces are in the same package.*/for (Class<?> intf : interfaces) {int flags = intf.getModifiers();if (!Modifier.isPublic(flags)) {accessFlags = Modifier.FINAL;String name = intf.getName();int n = name.lastIndexOf('.');String pkg = ((n == -1) ? "" : name.substring(0, n + 1));if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException("non-public interfaces from different packages");}}}if (proxyPkg == null) { // 包名就是com.sun.proxy// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}/** Choose a name for the proxy class to generate.*/long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num; // 依次递增/** Generate the specified proxy class.*/// 代理类生成器,返回字节数组,就是字节码byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);try {// classLoader加载类,是一个native方法,返回一个Class对象return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}}
}

(2)总结

vm options参数设置-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true,就可以把生成的代理类的源码保存在com.sun.proxy目录下面,或者用arthas来查看运行中的类信息。

JDK动态代理生成的代理类,我们通过反编译,发现其实是这个样子的:

package com.sun.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import com.demo.EchoService;public final class $Proxy0
extends Proxy
implements EchoService {private static Method m1;private static Method m3;private static Method m2;private static Method m0;public $Proxy0(InvocationHandler invocationHandler) {super(invocationHandler);}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m3 = Class.forName("com.demo.EchoService").getMethod("echo", Class.forName("java.lang.String"));m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);return;}catch (NoSuchMethodException noSuchMethodException) {throw new NoSuchMethodError(noSuchMethodException.getMessage());}catch (ClassNotFoundException classNotFoundException) {throw new NoClassDefFoundError(classNotFoundException.getMessage());}}public final boolean equals(Object object) {try {return (Boolean)this.h.invoke(this, m1, new Object[]{object});}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String toString() {try {return (String)this.h.invoke(this, m2, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final int hashCode() {try {return (Integer)this.h.invoke(this, m0, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String echo(String string) throws NullPointerException {try {return (String)this.h.invoke(this, m3, new Object[]{string});}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}
}

InvocationHandler就是Proxy.newProxyInstance传入的最后一个参数。

当调用代理对象的方法时,会执行InvocationHandler的invoke方法。

注意,JDK生成的代理类的包名不总是com.sun.proxy,只有当接口为Public时是这样的,当接口为非public时,生成的代理类与接口所在包名相同。

写在后面

如果本文对你有帮助,请点赞收藏关注一下吧 ~
在这里插入图片描述

相关文章:

深入理解JDK动态代理原理,使用javassist动手写一个动态代理框架

文章目录一、动手实现一个动态代理框架1、初识javassist2、使用javassist实现一个动态代理框架二、JDK动态代理1、编码实现2、基本原理&#xff08;1&#xff09;getProxyClass0方法&#xff08;2&#xff09;总结写在后面一、动手实现一个动态代理框架 1、初识javassist Jav…...

一、策略模式的使用

1、策略模式定义&#xff1a; 策略模式&#xff08;Strategy Pattern&#xff09;定义了一组策略&#xff0c;分别在不同类中封装起来&#xff0c;每种策略都可以根据当前场景相互替换&#xff0c;从而使策略的变化可以独立于操作者。比如我们要去某个地方&#xff0c;会根据距…...

Verilog使用always块实现时序逻辑

这篇文章将讨论 verilog 中一个重要的结构---- always 块&#xff08;always block&#xff09;。verilog 中可以实现的数字电路主要分为两类----组合逻辑电路和时序逻辑电路。与组合逻辑电路相反&#xff0c;时序电路电路使用时钟并一定需要触发器等存储元件。因此&#xff0c…...

面向对象设计模式:行为型模式之迭代器模式

一、迭代器模式&#xff0c;Iterator Pattern aka&#xff1a;Cursor Pattern 1.1 Intent 意图 Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. 提供一种按顺序访问聚合对象的元素而不公开其基…...

如何快速在企业网盘中找到想要的文件

现在越来越多的企业采用企业网盘来存储文档和资料&#xff0c;而且现在市面上的企业网盘各种各样。在使用企业网盘过程中&#xff0c;很多用户会问到企业网盘中如何快速搜索文件的问题。但是无论是“标签”功能还是普通的“关键词搜索”功能&#xff0c;都是单层级的&#xff0…...

香橙派5使用NPU加速yolov5的实时视频推理(二)

三、将best.onnx转为RKNN格式 这一步就需要我们进入到Ubuntu20.04系统中了&#xff0c;我的Ubuntu系统中已经下载好了anaconda&#xff0c;使用anaconda的好处就是可以方便的安装一些库&#xff0c;而且还可以利用conda来配置虚拟环境&#xff0c;做到环境与环境之间相互独立。…...

算法练习-二分查找(一)

算法练习-二分查找 1 代码实现 1.1 非递归实现 public int bsearch(int[] a, int n, int value) {int low 0;int high n - 1;while (low < high) {int mid (low high) / 2;if (a[mid] value) {return mid;} else if (a[mid] < value) {low mid 1} else {high …...

通用业务平台设计(五):预警平台建设

前言 在上家公司&#xff0c;随着业务的不断拓展(从支持单个国家单个主体演变成支持多个国家多个主体)&#xff0c;对预警的诉求越来越紧迫&#xff1b;如何保障业务的稳定性那&#xff1f;预警可以帮我们提前甄别风险&#xff0c;从而让我们可以在风险来临前将其消灭&#xff…...

Windows openssl-1.1.1d vs2017编译

工具&#xff1a; 1. perl&#xff08;https://strawberryperl.com/&#xff09; 2. nasm&#xff08;https://nasm.us/&#xff09; 3. openssl源码&#xff08;https://www.openssl.org/&#xff09; 可以自己去下载 或者我的网盘提供下载&#xff1a; 链接&#xff1a;…...

【深蓝学院】手写VIO第2章--IMU传感器--笔记

0. 内容 1. 旋转运动学 角速度的推导&#xff1a; 左ω∧\omega^{\wedge}ω∧&#xff0c;而ω\omegaω是在z轴方向运动&#xff0c;θ′[0,0,1]T\theta^{\prime}[0,0,1]^Tθ′[0,0,1]T 两边取模后得到结论&#xff1a; 线速度大小半径 * 角速度大小 其中&#xff0c;对旋转矩…...

网络基础(二)之HTTP与HTTPS

应用层 再谈 "协议" 协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢? 为什么要转换呢&#xff1f; 如果我们将struct message里面的信息…...

Python每日一练(20230306)

目录 1. 翻转二叉树 ★★ 2. 最长公共前缀 ★★ 3. 2的幂 ★ 1. 翻转二叉树 翻转一棵二叉树。 示例 1&#xff1a; 输入&#xff1a; 4/ \2 7/ \ / \ 1 3 6 9 输出&#xff1a; 4/ \7 2/ \ / \ 9 6 3 1示例 2&#xff1a; 输入&#xff1a; 1…...

C/C++每日一练(20230305)

目录 1. 整数分解 ☆ 2. 二叉树的最小深度 ★★ 3. 找x ★★ 1. 整数分解 输入一个正整数&#xff0c;将其按7进制位分解为各乘式的累加和。 示例 1&#xff1a; 输入&#xff1a;49 输出&#xff1a;497^2示例 2&#xff1a; 输入&#xff1a;720 输出&#xff1a;720…...

SAS字典的应用

数据字典中常用信息检索DICTIONARY.COLUMNS、DICTIONARY.TABLES以及DICTIONARY.MEMBERS等字典表的内容。在编程实践中&#xff0c;如何以SAS字典表来提高效率。 1、DICTIONARY.COLUMNS 对于当前SAS任务的全部数据集&#xff0c;表格DICTIONARY.COLUMNS包含了诸如变量的名称、类…...

Mysql中的函数和触发器

函数函数是什么&#xff1f;多用于查询语句&#xff0c;实现了某种功能&#xff1b;用途与存储过程不同&#xff0c;但语法是类似的&#xff1b;函数语法create function 函数名([参数列表]) returns 数据类型 begin DECLARE 变量&#xff1b; sql 语句; return 值; end; 设置函…...

分布式架构之(Zookeeper原理)

Zookeeper是一个典型的分布式数据一致性的结局方案&#xff0c;分布式应用程序可以基于它实现注入数据发布、订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能&#xff0c; Zookeeper可以保证如下分布式一致性特性&#xff1a; 顺…...

Java框架学习 | MyBatis

问题导向学习MyBatis 为什么要有MyBatis框架&#xff1f; 避免Java开发者直接使用 JDBC重复做数据库操作&#xff0c;同时更便捷地实现想要的数据库相关功能&#xff0c;让Java专注于开发业务。 MyBatis框架如何实现该目的&#xff1f; MyBatis是半自动化持久层ORM框架&#x…...

Cookie+Session详解

文章目录批量删除会话技术简介CookieCookie 查看Cookie 的删除Cookie 使用页面获取 cookie 信息cookie 特点Sessionsession 的使用Session 登录权限验证过滤器简介过滤器的使用WebFilter 注解过滤放行登录权限验证批量删除 servlet 类 dao 层 会话技术 简介 在计算机领域…...

CAPL脚本要注意区分elcount和strlen求数组长度的区别,不然要吃大亏

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…...

CSS常用选择器

目录 1.CSS是什么 2.CSS的三种写法 2.1内部样式 2.2内联样式 2.3外部样式 3.CSS选择器 3.1标签选择器 3.2类选择器(更好的选择) 3.3ID选择器 3.4后代选择器 3.5子选择器 3.6并集选择器 3.7伪类选择器(复合选择器的特殊用法) 1.CSS是什么 CSS全称Cascding Style Sh…...

Registry与DGC的攻击利用

0x01 2022-02-03写的一篇文章。 0x02 Registry Registry指的是RMI的注册表&#xff0c;攻击的目标是注册表所在的机器&#xff0c;一般注册表和RMI Server在同一个机器上&#xff0c;特殊情况下也会在不同机器上。 在我们通过LocateRegistry#getRegistry获取到目标开启的注…...

赛道持续降温!又一家自动驾驶公司裁员,市值曾超50亿美元

从去年下半年开始&#xff0c;自动驾驶赛道的裁员、倒闭风潮盛行。 本周&#xff0c;美股卡车自动驾驶上市公司Embark Trucks&#xff08;EMBK&#xff09;宣布将裁员70%&#xff0c;同时大幅缩减业务。“痛苦可能还没有结束&#xff0c;”公司首席执行官Alex Rodrigues在给员…...

路径规划 | 图解动态A*(D*)算法(附ROS C++/Python/Matlab仿真)

目录0 专栏介绍1 什么是D*算法&#xff1f;2 D*算法核心概念一览3 D*算法流程图4 步步图解&#xff1a;算法实例5 算法仿真与实现5.1 ROS C实现5.2 Python实现0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详…...

GraphCut、最大流最小割定理

G&#xff08;V&#xff0c;E&#xff09;&#xff1b;V为点集&#xff0c;E为边集&#xff1b; 节点集V中的节点分为&#xff1a; &#xff08;1&#xff09;终端节点。不包含图像像素&#xff0c;用S和T表示。S为源点&#xff0c;T为汇点。图像分割中通常用S表示前景目标&a…...

Word文档的密码忘记了怎么办?

Word文档可以设置两种密码&#xff0c;文件的“限制密码”和“打开密码”&#xff0c;今天来分享一下忘记这两种密码可以如何处理。 如果忘记的是Word文档的“限制密码”&#xff0c;文档就无法编辑及更改了&#xff0c;菜单目录中的相关选项也都是灰色状态&#xff0c;无法点…...

Java分布式事务(二)

文章目录&#x1f525;分布式事务处理_认识本地事务&#x1f525;关系型数据库事务基础_并发事务带来的问题&#x1f525;关系型数据库事务基础_MySQL事务隔离级别&#x1f525;MySQL事务隔离级别_模拟异常发生之脏读&#x1f525;MySQL事务隔离级别_模拟异常发生之不可重复读&…...

游戏项目中的程序化生成(PCG):算法之外的问题与问题

本篇讨论的是什么 从概念上讲&#xff0c;PCG&#xff08;程序化生成&#xff09;的含义很广&#xff1a;任何通过规则计算得到的内容&#xff0c;都可算作是PCG。但在很多游戏项目的资料&#xff0c;包括本篇&#xff0c;讨论PCG时特指是&#xff1a;用一些算法/工具(特别是H…...

【C++】位图+哈希切割+布隆过滤器

文章目录一、位图1.1 位图概念1.2 位图实现1.2.1 把x对应比特位0置11.2.2 把x对应比特位1置01.2.1 查看x对应比特位1.3 位图源码1.4 位图的应用二、哈希切割&#xff08;处理海量数据&#xff09;三、布隆过滤器3.1 布隆过滤器的概念3.2 布隆过滤器的应用场景3.3 布隆过滤器的实…...

python实现网络游戏NPC任务脚本引擎(带限时任务功能)

python实现NPC任务脚本引擎 一、简介二、简单示例三、实现任务限时的功能四、结合twisted示例一、简介 要实现面向对象的网络游戏NPC任务脚本引擎,可以采用以下步骤: 1.定义NPC类:该类应该包括NPC的基本属性和行为,如名字、位置、血量、攻击力等等。NPC还应该有任务的列表…...

C语言的原子操作(待完善)

文章目录一、什么是原子操作二、为什么需要原子操作三、API一、什么是原子操作 原子操作是不可分割的&#xff0c;在执行完毕之前不会被任何其它任务或事件中断&#xff0c;可以视为最小的操作单元&#xff0c;是在执行的过程中、不会导致对数据的并发访问的、最小操作&#x…...