看故事学知识,这篇Java代理的文章妙啊!

这是我的第 208 期分享

作者 | java金融

来源 | java金融(ID:java4299)

分享 | Java中文社群(ID:javacn666)

什么是代理

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

代理其实不仅仅是在软件开发领域,在我们的日常生活中也是时常可见。比如某p2p老板突然携款带着小姨子跑路了,可怜了下面一堆的程序员背负一身房贷,上有老下有小,程序员只能被迫去申请劳动仲裁,劳动局就会为其指派一位代理律师全权负责程序员的仲裁事宜(PS:p2p跑路仲裁拿回工资的可能性非常低,没让你把工资退回就算好的了)。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理程序员。比如:房东要将房子出售,于是到房地产中介公司找一个中介(代理),由他来帮房东完成销售房屋,签订合同、网签、贷款过户等等事宜。

代理模式

这是常见代理模式常见的 UML 示意图。 需要注意的有下面几点:

  1. 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject

  2. 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。

  3. 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。

  4. 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作。

  • 代理又可以分为静态代理和动态代理两种。我们先来看下静态代理。

静态代理

电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如提供按摩椅,娃娃机(这个每次去电影院都会尝试下,基本上是夹不起来,有木有大神可以传授下诀窍),卖爆米花、饮料(贵的要死,反正吃不起)等。我们平常去电影院看电影的时候,在电影开始的阶段是不是经常会放广告呢?然后在影片开始结束时播放一些广告。 下面我们通过代码来模拟下电影院这一系列的赚钱操作。 首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力。

package com.workit.demo.proxy;public interface Movie {void play();
}
  • 接下来我们要创建一个真正的实现这个 Movie 接口的类,和一个实现该接口的代理类。 真正的类《美国队长》电影:

package com.workit.demo.proxy;public class CaptainAmericaMovie implements Movie {@Overridepublic void play() {System.out.println("普通影厅正在播放的电影是《美国队长》");}
}

代理类:

package com.workit.demo.proxy;public class MovieStaticProxy implements Movie {Movie movie;public MovieStaticProxy(Movie movie) {this.movie = movie;}@Overridepublic void play() {playStart();movie.play();playEnd();}public void playStart() {System.out.println("电影开始前正在播放广告");}public void playEnd() {System.out.println("电影结束了,接续播放广告");}
}

测试类:

package com.workit.demo.proxy;package com.workit.demo.proxy;public class StaticProxyTest {public static void main(String[] args) {Movie captainAmericaMovie = new CaptainAmericaMovie();Movie movieStaticProxy = new MovieStaticProxy(captainAmericaMovie);movieStaticProxy.play();}
}

运行结果:

电影开始前正在播放广告
正在播放的电影是《美国队长》
电影结束了,接续播放广告

现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。这个就是是静态代理的内容,为什么叫做静态呢?因为它的类型是事先预定好的,比如上面代码中的 MovieStaticProxy 这个类。

优点
  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用

  • 代理对象可以扩展目标对象的功能

  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度。

缺点
  • 代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护。

jdk动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

  • 接着上面的例子,刚看完《美国队长》不过瘾,还想继续去看一场《钢铁侠》。一直在普通影厅看电影觉得没啥意思,那就赶紧去VIP影厅(至今不知道长啥样子)体验一把。既然 实体店没体验过那就用代码来体验一次吧。创建一个VIPMovie电影接口

package com.workit.demo.proxy;
public interface VIPMovie {void vipPlay();
}

紧接着创建一个VIP影厅的播放实现类

package com.workit.demo.proxy;public class IronManVIPMovie implements VIPMovie {@Overridepublic void vipPlay() {System.out.println("VI影厅正在播放的电影是《钢铁侠》");}
}

如果按照静态代理我们是不是又要创建一个VIP影厅播放的代理实现类,这种方式我们就不演示了。下面我们来看看通过动态代理怎么来实现吧。

package com.workit.demo.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {private Object object;public MyInvocationHandler(Object object) {this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {playStart();Object invoke = method.invoke(object, args);playEnd();return invoke;}public void playStart() {System.out.println("电影开始前正在播放广告");}public void playEnd() {System.out.println("电影结束了,接续播放广告");}
}

MyInvocationHandler实现了 InvocationHandler 这个类,这个类是什么意思呢?大家不要慌张,下面我会解释。然后,我们就可以在VIP影厅看电影了。

package com.workit.demo.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;public class DynamicProxyTest {public static void main(String[] args) {IronManVIPMovie ironManVIPMovie = new IronManVIPMovie();InvocationHandler invocationHandler = new MyInvocationHandler(ironManVIPMovie);VIPMovie dynamicProxy = (VIPMovie) Proxy.newProxyInstance(IronManVIPMovie.class.getClassLoader(),IronManVIPMovie.class.getInterfaces(), invocationHandler);dynamicProxy.vipPlay();}
}

输出结果:

电影开始前正在播放广告
VI影厅正在播放的电影是《钢铁侠》
电影结束了,接续播放广告

看到没有,我们并没有像静态代理那样为 VIPMovie接口实现一个代理类,但最终它仍然实现了相同的功能,这其中的差别,就是之前讨论的动态代理所谓“动态”的原因。 我们顺带把《美国队长》也用动态代理实现下吧。

package com.workit.demo.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;public class DynamicProxyTest {public static void main(String[] args) {// VIP 影厅《钢铁侠》IronManVIPMovie ironManVIPMovie = new IronManVIPMovie();InvocationHandler invocationHandler = new MyInvocationHandler(ironManVIPMovie);VIPMovie dynamicProxy = (VIPMovie) Proxy.newProxyInstance(IronManVIPMovie.class.getClassLoader(),IronManVIPMovie.class.getInterfaces(), invocationHandler);dynamicProxy.vipPlay();// 普通影厅《美国队长》CaptainAmericaMovie captainAmericaMovie = new CaptainAmericaMovie();InvocationHandler invocationHandler1 = new MyInvocationHandler(captainAmericaMovie);Movie dynamicProxy1 = (Movie) Proxy.newProxyInstance(CaptainAmericaMovie.class.getClassLoader(),CaptainAmericaMovie.class.getInterfaces(), invocationHandler1);dynamicProxy1.play();}
}

输出结果:

电影开始前正在播放广告
VI影厅正在播放的电影是《钢铁侠》
电影结束了,接续播放广告
电影开始前正在播放广告
正在播放的电影是《美国队长》
电影结束了,接续播放广告

我们通过 Proxy.newProxyInstance() 方法,却产生了 Movie和 VIPMovie两种接口的实现类代理,这就是动态代理的魔力。

JDK动态代理到底是怎么实现的呢

动态代码涉及了一个非常重要的类 Proxy。正是通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。具体怎么去创建代理类就不分析了,感兴趣的可以去看下源码。我们直接看下生成的代理类。 如何查看生成的代理类? 在生成代理类之前加上以下代码(我用的jdk1.8):

 //新版本 jdk产生代理类   System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

如果上述代码加上不生效可以考虑加下下面的代码:

// 老版本jdk
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//  该设置用于输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\class");  

代码如下:

  public static void main(String[] args) {//新版本 jdk产生代理类System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");// VIP 影厅《钢铁侠》IronManVIPMovie ironManVIPMovie = new IronManVIPMovie();InvocationHandler invocationHandler = new MyInvocationHandler(ironManVIPMovie);VIPMovie dynamicProxy = (VIPMovie) Proxy.newProxyInstance(IronManVIPMovie.class.getClassLoader(),IronManVIPMovie.class.getInterfaces(), invocationHandler);dynamicProxy.vipPlay();// 普通影厅《美国队长》CaptainAmericaMovie captainAmericaMovie = new CaptainAmericaMovie();InvocationHandler invocationHandler1 = new MyInvocationHandler(captainAmericaMovie);Movie dynamicProxy1 = (Movie) Proxy.newProxyInstance(CaptainAmericaMovie.class.getClassLoader(),CaptainAmericaMovie.class.getInterfaces(), invocationHandler1);dynamicProxy1.play();System.out.println("VIP 影厅《钢铁侠》代理类:"+dynamicProxy.getClass());System.out.println("普通影厅《美国队长》:"+dynamicProxy1.getClass());}

我们可以看到结果

电影开始前正在播放广告
VI影厅正在播放的电影是《钢铁侠》
电影结束了,接续播放广告
电影开始前正在播放广告
正在播放的电影是《美国队长》
电影结束了,接续播放广告
VIP 影厅《钢铁侠》代理类:class com.sun.proxy.$Proxy0
普通影厅《美国队长》:class com.sun.proxy.$Proxy1

产生了两个代理类分别是$Proxy0$Proxy1。 下面们来看下"钢铁侠"的代理类$Proxy0

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.sun.proxy;import com.workit.demo.proxy.VIPMovie;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements VIPMovie {private static Method m1;private static Method m3;private static Method m2;private static Method m0;public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final void vipPlay() throws  {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String toString() throws  {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws  {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m3 = Class.forName("com.workit.demo.proxy.VIPMovie").getMethod("vipPlay");m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
},

通过上述代码我们可以看到 $Proxy0 extends Proxy implements VIPMovie继承了Proxy 且实现了VIPMovie接口,这也就是为什么jdk动态代理必须基于接口,java 是单继承的。 然后再看下代理类实现的方法:

 public final void vipPlay() throws  {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}

这个supper.h.invoke Proxy中的h的invoke方法,即InvocationHandler.invoke也就是上面 MyInvocationHandler.invoke方法,至此整个流程就清晰了。这就是jdk的动态代理。

cglib动态代理

上面说jdk动态代理只能基于接口,那么如果是类要动态代理怎么办呢?cglib动态代理就可解决关于类的动态代理。 下面我们来创建一个“《美国队长2》”

package com.workit.demo.proxy;public class CaptainAmerica2MovieImpl {public void play(){System.out.println("正在播放的电影是《美国队长2》");}
}

引入cglib pom依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

创建一个自定义MethodInterceptor。

package com.workit.demo.proxy;import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CglibProxyInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {playStart();Object object = methodProxy.invokeSuper(o, objects);playEnd();return object;}public void playStart() {System.out.println("电影开始前正在播放广告");}public void playEnd() {System.out.println("电影结束了,接续播放广告");}
}

测试类

package com.workit.demo.proxy;import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;public class CglibProxyTest {public static void main(String[] args) {// //在指定目录下生成动态代理类System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\class");//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数Enhancer enhancer = new Enhancer();//设置目标类的字节码文件enhancer.setSuperclass(CaptainAmerica2MovieImpl.class);//设置回调函数enhancer.setCallback(new CglibProxyInterceptor());//这里的creat方法就是正式创建代理类CaptainAmerica2MovieImpl captainAmerica2Movie = (CaptainAmerica2MovieImpl)enhancer.create();//调用代理类的play方法captainAmerica2Movie.play();System.out.println("cglib动态代理《美国队长2》:"+captainAmerica2Movie.getClass());}
}

输出结果:

电影开始前正在播放广告
正在播放的电影是《美国队长2》
电影结束了,接续播放广告
cglib动态代理《美国队长2》:class com.workit.demo.proxy.CaptainAmerica2MovieImpl$$EnhancerByCGLIB$$5c3ddcfe

我们看下最终创建的代理类生成的play方法

public class CaptainAmerica2MovieImpl$$EnhancerByCGLIB$$5c3ddcfe extends CaptainAmerica2MovieImpl implements Factory {public final void play() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$play$0$Method, CGLIB$emptyArgs, CGLIB$play$0$Proxy);} else {super.play();}}

从代理对象反编译源码可以知道,代理对象继承于CaptainAmerica2MovieImpl ,拦截器调用intercept()方法, intercept()方法由自定义CglibProxyInterceptor实现,所以,最后调用CglibProxyInterceptor中的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

  • CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

  • 用CGlib生成代理类是目标类的子类。

  • 用CGlib生成 代理类不需要接口。

  • 用CGLib生成的代理类重写了父类的各个方法。

  • 拦截器中的intercept方法内容正好就是代理类中的方法体。

总结

  • 代理分为静态代理和动态代理两种。

  • 静态代理,代理类需要自己编写代码写成。

  • 动态代理有jdk和cglib,代理类通过 Proxy.newInstance()或者ASM 生成。

  • 静态代理和动态代理的区别是在于要不要开发者自己定义 Proxy 类。 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 或者 MethodInterceptor的实现类。

  • 代理模式本质上的目的是为了增强现有代码的功能。

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

参考

https://blog.csdn.net/m0_37314675/article/details/77850967 https://www.cnblogs.com/cC-Zhou/p/9525638.html https://www.jianshu.com/p/4539e6d9f337

往期推荐

啪啪打脸!领导说:try-catch要放在循环体外!

阿里巴巴为什么让初始化集合时必须指定大小?

关注公众号发送”进群“,磊哥拉你进读者群。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/546089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[下载]青岛交通旅游地图[download]

清闲无事 所以就把青岛地图扫描了一下有需要青岛旅游地图的可以下载the download 【下载】

Java Thread类的静态void sleep(long time_in_ms)方法,带示例

线程类静态无效睡眠(long time_in_ms) (Thread Class static void sleep(long time_in_ms)) This method is available in package java.lang.Thread.sleep(long time_in_ms). 软件包java.lang.Thread.sleep(long time_in_ms)中提供了此方法。 sleep(long time_in_ms) method i…

阿里《Java开发手册》中的 1 个bug!

这是我的第 210 期分享作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;本来打算写一篇《阿里巴巴为什么不允许日志输出时&#xff0c;使用字符串拼接&#xff1f;》的文章&a…

zoj 1006 do the untwist

题目见zoj 1006 或poj 1317 简单的解密算法&#xff0c;直接套用题目中公式即可。 /* zoj 1006 Do the Untwist */ #include <stdio.h> #include <string.h>#define MAXLEN 80 #define MAGICNUM 28char num2Char(int n); int char2Num(char c); int main(void)…

安装完SqlServer2008,wamp服务器无法启动的问题

"开始"->"程序"->Microsoft SQL Server 2008->配置工具->SQL Server配置管理器->SQL Server服务: 只保留SQL Server(MSSQLSERVER)(正在运行)&#xff0c;其他的全部设为停止。 重启wamp服务器成功!

猫版超级玛丽 附下载

不再多言 玩者自知しょぼんのアクション猫版超级玛丽 下载

驳《阿里「Java开发手册」中的1个bug》?

这是我的第 211 期分享作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;前两天写了一篇关于《阿里Java开发手册中的 1 个bug》的文章&#xff0c;评论区有点炸锅了&#xff0…

Java String indexOf(String substr,int fromIndex)方法,带示例

字符串indexOf(String substr&#xff0c;int fromIndex)方法 (String indexOf(String substr, int fromIndex) Method) indexOf(String substr, int fromIndex) is a String method in Java and it is used to get the index of a specified substring in the string from giv…

zoj 1078 palindrom numbers

题目见zoj 1078 主要是判断一个整数在基数为2-16之间的某个数字时是否为回文&#xff0c;我是直接该整数转换成对应基数的表示的逆序列&#xff0c;并计算出该表示下的值&#xff0c;判断是否等于这个整数值&#xff0c;如果相等&#xff0c;那么就是回文&#xff0c;如果不相…

iredmail邮件服务器之修改默认的web服务端口号

安装iredmail之后&#xff0c;由于需要在路由器上做端口映射以便在外网访问webmail&#xff0c;因此端口不能和WEB服务的端口好冲突&#xff0c;所以需要修改邮件服务器的httpd服务的端口。 一、apache/httpd的http服务和https服务端口号都要修改。 基本服务端口好办&#xff0…

轻松学算法的秘密!可视化算法网站汇总!(附动图)

对于「算法」的第一印象&#xff0c;我相信大部分人都是一样的&#xff0c;就是一个“难”字了得。而我比较特殊&#xff0c;我的第一印象、第二印象以至第 N 印象都觉得很难&#xff0c;所以为了更好的学习和理解算法&#xff0c;我千金一掷一下买了一堆的算法书&#xff0c;有…

从100套真题中提炼而出的100个经典句子

1. Typical of the grassland dwellers of the continent is the American antelope, or pronghorn. 1.美洲羚羊&#xff0c;或称叉角羚&#xff0c;是该大陆典型的草原动物。 2. Of the millions who saw Haley’s comet in 1986, how many people will live long enough to s…

字符串大写转小写库函数_PHP程序无需使用库函数即可将字符串转换为大写

字符串大写转小写库函数Given a string and we have to convert it into uppercase string without using any library function. 给定一个字符串&#xff0c;我们必须在不使用任何库函数的情况下将其转换为大写字符串。 PHP code: PHP代码&#xff1a; <?php//function …

zoj 1091 Knight Moves

题目见zoj 1091 使用宽度搜索优先来求解&#xff0c;这个算法已经忘记的差不多了&#xff0c;所以写出来的代码很罗嗦&#xff0c;看起来很不清晰。 好像还可以直接用公式或者神经网络算法求解,详见Knights Tour /* zoj 1091 Knight Moves */ #include <stdio.h> #incl…

1.基本类型的指针

例子一&#xff1a; #include<stdio.h>int main() {int i10;int * p&i; //p是个变量名字&#xff0c;int * 表示该p变量只能存储int类型变量的地址。//int *p&i;等价于 int *p; p&i;//p存放了i的地址,p指向i,*p就是i变量本身printf("%d\n",p);// …

VB中KeyCode常数用法 VB 按键

VB中KeyCode常数用法可在代码中的任何地方用下列常数代替实际值&#xff1a;常数 值 描述vbKeyLButton 0x1 鼠标左键vbKeyRButton 0x2 鼠标右键vbKeyCancel 0x3 CANCEL 键vbKeyMButton 0x4 鼠标中键vbKeyBack 0x8 BACKSPACE 键vbKeyTab 0x9 TAB 键vbKeyClear 0xC CLEAR 键vbKey…

zoj 1088 System Overload

约瑟夫环 (josephus problem &#xff09;问题&#xff0c;有公式 可以直接套用 我使用暴力破解方法求解&#xff08;用时3秒多&#xff09;。 代码如下&#xff1a; /* zoj 1088 System Overload */ #include <stdio.h> #include <string.h>#define MAXBUILDING …

链表竟然比数组慢了1000多倍?(动图+性能评测)

这是我的第 215 期分享作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;数组和链表是程序中常用的两种数据结构&#xff0c;也是面试中常考的面试题之一。然而对于很多人来说…

c语言用宏定义常量_使用宏定义常量以在C的数组声明中使用

c语言用宏定义常量As we know that, while declaring an array we need to pass maximum number of elements, for example, if you want to declare an array for 10 elements. You need to pass 10 while declaring. Example: int arr[10]; 众所周知&#xff0c;在声明数组时…