代理(Proxy)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

一、代理的概念

  动态代理技术是整个java技术中最重要的一个技术,它是学习java框架的基础,不会动态代理技术,那么在学习Spring这些框架时是学不明白的。

  动态代理技术就是用来产生一个对象的代理对象的。在开发中为什么需要为一个对象产生代理对象呢?
  举一个现实生活中的例子:歌星或者明星都有一个自己的经纪人,这个经纪人就是他们的代理人,当我们需要找明星表演时,不能直接找到该明星,只能是找明星的代理人。比如刘德华在现实生活中非常有名,会唱歌,会跳舞,会拍戏,刘德华在没有出名之前,我们可以直接找他唱歌,跳舞,拍戏,刘德华出名之后,他干的第一件事就是找一个经纪人,这个经纪人就是刘德华的代理人(代理),当我们需要找刘德华表演时,不能直接找到刘德华了(刘德华说,你找我代理人商谈具体事宜吧!),只能是找刘德华的代理人,因此刘德华这个代理人存在的价值就是拦截我们对刘德华的直接访问!
  这个现实中的例子和我们在开发中是一样的,我们在开发中之所以要产生一个对象的代理对象,主要用于拦截对真实业务对象的访问。那么代理对象应该具有什么方法呢?代理对象应该具有和目标对象相同的方法

  所以在这里明确代理对象的两个概念:
    1、代理对象存在的价值主要用于拦截对真实业务对象的访问
    2、代理对象应该具有和目标对象(真实业务对象)相同的方法。刘德华(真实业务对象)会唱歌,会跳舞,会拍戏,我们现在不能直接找他唱歌,跳舞,拍戏了,只能找他的代理人(代理对象)唱歌,跳舞,拍戏,一个人要想成为刘德华的代理人,那么他必须具有和刘德华一样的行为(会唱歌,会跳舞,会拍戏),刘德华有什么方法,他(代理人)就要有什么方法,我们找刘德华的代理人唱歌,跳舞,拍戏,但是代理人不是真的懂得唱歌,跳舞,拍戏的,真正懂得唱歌,跳舞,拍戏的是刘德华,在现实中的例子就是我们要找刘德华唱歌,跳舞,拍戏,那么只能先找他的经纪人,交钱给他的经纪人,然后经纪人再让刘德华去唱歌,跳舞,拍戏。

二、java中的代理

2.1、"java.lang.reflect.Proxy"类介绍

  现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。在java中如何用程序去生成一个对象的代理对象呢,java在JDK1.5之后提供了一个"java.lang.reflect.Proxy"类,通过"Proxy"类提供的一个newProxyInstance方法用来创建一个对象的代理对象,如下所示:

1 static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

  newProxyInstance方法用来返回一个代理对象,这个方法总共有3个参数,ClassLoader loader用来指明生成代理对象使用哪个类装载器,Class<?>[] interfaces用来指明生成哪个对象的代理对象,通过接口指定,InvocationHandler h用来指明产生的这个代理对象要做什么事情。所以我们只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。

2.2、编写生成代理对象的类

  在java中规定,要想产生一个对象的代理对象,那么这个对象必须要有一个接口,所以我们第一步就是设计这个对象的接口,在接口中定义这个对象所具有的行为(方法)

  1、定义对象的行为接口

package cn.gacl.proxy;/**
* @ClassName: Person
* @Description: 定义对象的行为
* @author: 孤傲苍狼
* @date: 2014-9-14 下午9:44:22
*
*/ 
public interface Person {/*** @Method: sing* @Description: 唱歌* @Anthor:孤傲苍狼** @param name* @return*/ String sing(String name);/*** @Method: sing* @Description: 跳舞* @Anthor:孤傲苍狼** @param name* @return*/ String dance(String name);
}

  2、定义目标业务对象类

package cn.gacl.proxy;/**
* @ClassName: LiuDeHua
* @Description: 刘德华实现Person接口,那么刘德华会唱歌和跳舞了
* @author: 孤傲苍狼
* @date: 2014-9-14 下午9:22:24
*
*/ 
public class LiuDeHua implements Person {public String sing(String name){System.out.println("刘德华唱"+name+"歌!!");return "歌唱完了,谢谢大家!";}public String dance(String name){System.out.println("刘德华跳"+name+"舞!!");return "舞跳完了,多谢各位观众!";}
}

  3、创建生成代理对象的代理类

package cn.gacl.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/**
* @ClassName: LiuDeHuaProxy
* @Description: 这个代理类负责生成刘德华的代理人
* @author: 孤傲苍狼
* @date: 2014-9-14 下午9:50:02
*
*/ 
public class LiuDeHuaProxy {//设计一个类变量记住代理类要代理的目标对象private Person ldh = new LiuDeHua();/*** 设计一个方法生成代理对象* @Method: getProxy* @Description: 这个方法返回刘德华的代理对象:Person person = LiuDeHuaProxy.getProxy();//得到一个代理对象* @Anthor:孤傲苍狼** @return 某个对象的代理对象*/ public Person getProxy() {//使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某个对象的代理对象return (Person) Proxy.newProxyInstance(LiuDeHuaProxy.class.getClassLoader(), ldh.getClass().getInterfaces(),new InvocationHandler() {/*** InvocationHandler接口只定义了一个invoke方法,因此对于这样的接口,我们不用单独去定义一个类来实现该接口,* 而是直接使用一个匿名内部类来实现该接口,new InvocationHandler() {}就是针对InvocationHandler接口的匿名实现类*//*** 在invoke方法编码指定返回的代理对象干的工作* proxy : 把代理对象自己传递进来 * method:把代理对象当前调用的方法传递进来 * args:把方法参数传递进来* * 当调用代理对象的person.sing("冰雨");或者 person.dance("江南style");方法时,* 实际上执行的都是invoke方法里面的代码,* 因此我们可以在invoke方法中使用method.getName()就可以知道当前调用的是代理对象的哪个方法*/@Overridepublic Object invoke(Object proxy, Method method,Object[] args) throws Throwable {//如果调用的是代理对象的sing方法if (method.getName().equals("sing")) {System.out.println("我是他的经纪人,要找他唱歌得先给十万块钱!!");//已经给钱了,经纪人自己不会唱歌,就只能找刘德华去唱歌!return method.invoke(ldh, args); //代理对象调用真实目标对象的sing方法去处理用户请求}//如果调用的是代理对象的dance方法if (method.getName().equals("dance")) {System.out.println("我是他的经纪人,要找他跳舞得先给二十万块钱!!");//已经给钱了,经纪人自己不会唱歌,就只能找刘德华去跳舞!return method.invoke(ldh, args);//代理对象调用真实目标对象的dance方法去处理用户请求}return null;}});}
}

  测试代码:

package cn.gacl.proxy;public class ProxyTest {public static void main(String[] args) {LiuDeHuaProxy proxy = new LiuDeHuaProxy();//获得代理对象Person p = proxy.getProxy();//调用代理对象的sing方法String retValue = p.sing("冰雨");System.out.println(retValue);//调用代理对象的dance方法String value = p.dance("江南style");System.out.println(value);}
}

  运行结果如下:

  105856_qNQj_1169289.png  

      Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
  由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。

三、动态代理应用

  在动态代理技术里,由于不管用户调用代理对象的什么方法,都是调用开发人员编写的处理器的invoke方法(这相当于invoke方法拦截到了代理对象的方法调用)。并且,开发人员通过invoke方法的参数,还可以在拦截的同时,知道用户调用的是什么方法,因此利用这两个特性,就可以实现一些特殊需求,例如:拦截用户的访问请求,以检查用户是否有访问权限、动态为某个对象添加额外的功能。

3.1、在字符过滤器中使用动态代理解决中文乱码

  在平时的JavaWeb项目开发中,我们一般会写一个CharacterEncodingFilter(字符过滤器)来解决整个JavaWeb应用的中文乱码问题,如下所示:

package me.gacl.web.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;/**
* @ClassName: CharacterEncodingFilter
* @Description: 解决中文乱码的字符过滤器
* @author: 孤傲苍狼
* @date: 2014-9-14 下午10:38:12
*
*/ 
public class CharacterEncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {//解决以Post方式提交的中文乱码问题request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");chain.doFilter(request, response);}@Overridepublic void destroy() {}
}

  但是这种写法是没有办法解决以get方式提交中文参数时的乱码问题的,我们可以用如下的代码来证明上述的解决中文乱码过滤器只对以post方式提交中文参数时有效,而对于以get方式提交中文参数时无效

  jsp测试页面如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%--引入jstl标签库 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML>
<html><head><title>使用字符过滤器解决解决get、post请求方式下的中文乱码问题</title></head><body><%--使用c:url标签构建url,构建好的url存储在servletDemo1变量中--%><c:url value="/servlet/ServletDemo1" scope="page" var="servletDemo1"><%--构建的url的附带的中文参数 ,参数名是:username,值是:孤傲苍狼--%><c:param name="username" value="孤傲苍狼"></c:param></c:url><%--使用get的方式访问 --%><a href="${servletDemo1}">超链接(get方式请求)</a><hr/><%--使用post方式提交表单 --%><form action="${pageContext.request.contextPath}/servlet/ServletDemo1" method="post">用户名:<input type="text" name="username" value="孤傲苍狼" /><input type="submit" value="post方式提交"></form></body>
</html>

  处理请求的ServletDemo1代码如下:

package me.gacl.web.controller;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class ServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 接收参数String username = request.getParameter("username");// 获取请求方式String method = request.getMethod();// 获取输出流PrintWriter out = response.getWriter();out.write("请求的方式:" + method);out.write("<br/>");out.write("接收到的参数:" + username);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}
}

  在web.xml中注册上述的CharacterEncodingFilter和ServletDemo1

<filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>me.gacl.web.filter.CharacterEncodingFilter</filter-class></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>ServletDemo1</servlet-name><servlet-class>me.gacl.web.controller.ServletDemo1</servlet-class></servlet><servlet-mapping><servlet-name>ServletDemo1</servlet-name><url-pattern>/servlet/ServletDemo1</url-pattern></servlet-mapping>

  测试结果如下所示:

  

  从运行结果可以看出,上述的过滤器的确是不能解决以get方式提交中文参数的乱码问题,下面使用动态代理技术改造上述的过滤器,使之能够解决以get方式提交中文参数的乱码问题,改造后的过滤器代码如下:

package me.gacl.web.filter;import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/**
* @ClassName: CharacterEncodingFilter
* @Description: 解决中文乱码的字符过滤器
* @author: 孤傲苍狼
* @date: 2014-9-14 下午10:38:12
*
*/ 
public class CharacterEncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {final HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;//解决以Post方式提交的中文乱码问题request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");//获取获取HttpServletRequest对象的代理对象ServletRequest requestProxy = getHttpServletRequestProxy(request);/*** 传入代理对象requestProxy给doFilter方法,* 这样用户在使用request对象时实际上使用的是HttpServletRequest对象的代理对象requestProxy*/chain.doFilter(requestProxy, response);}/*** @Method: getHttpServletRequestProxy* @Description: 获取HttpServletRequest对象的代理对象* @Anthor:孤傲苍狼** @param request* @return HttpServletRequest对象的代理对象*/ private ServletRequest getHttpServletRequestProxy(final HttpServletRequest request){ServletRequest proxy  = (ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(),request.getClass().getInterfaces(),new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//如果请求方式是get并且调用的是getParameter方法if (request.getMethod().equalsIgnoreCase("get") && method.getName().equals("getParameter")) {//调用getParameter方法获取参数的值String value = (String) method.invoke(request, args);if(value==null){return null;}//解决以get方式提交的中文乱码问题return new String(value.getBytes("iso8859-1"),"UTF-8");}else {//直接调用相应的方法进行处理return method.invoke(request, args);}}});//返回HttpServletRequest对象的代理对象return proxy;}@Overridepublic void destroy() {}
}

  我们在过滤器中使用动态代理技术生成一个HttpServletRequest对象的代理对象requestProxy,然后把代理对象requestProxy进行chain.doFilter(requestProxy, response)传递给用户使用,这样用户实际上使用的就是HttpServletRequest对象的代理对象requestProxy。然而这一过程对于用户来说是透明的,用户是不知道自己使用的HttpServletRequest对象是一个代理对象requestProxy,由于代理对象requestProxy和目标对象HttpServletRequest具有相同的方法,当用户调用getParameter方法接收中文参数时,实际上调用的就是代理对象requestProxy的invoke方法,因此我们就可以在invoke方法中就判断当前的请求方式以及用户正在调用的方法,如果判断当前的请求方式是get方式并且用户正在调用的是getParameter方法,那么我们就可以手动处理get方式提交中文参数的中文乱码问题了。

  测试结果如下所示:

  

 3.2、在字符过滤器中使用动态代理压缩服务器响应的内容后再输出到客户端

  压缩过滤器的代码如下:

package me.gacl.web.filter;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.zip.GZIPOutputStream;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/**
* @ClassName: GzipFilter
* @Description: 压缩过滤器,将web应用中的文本都经过压缩后再输出到浏览器
* @author: 孤傲苍狼
* @date: 2014-9-15 下午9:35:36
*
*/ 
public class GzipFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {final HttpServletRequest request = (HttpServletRequest) req;final HttpServletResponse response = (HttpServletResponse) resp;final ByteArrayOutputStream bout = new ByteArrayOutputStream();final PrintWriter pw = new PrintWriter(new OutputStreamWriter(bout,"UTF-8"));chain.doFilter(request, getHttpServletResponseProxy(response, bout, pw));pw.close();//拿到目标资源的输出byte result[] = bout.toByteArray();System.out.println("原始大小:" + result.length);ByteArrayOutputStream bout2 = new ByteArrayOutputStream();GZIPOutputStream gout = new GZIPOutputStream(bout2);gout.write(result);gout.close();//拿到目标资源输出的压缩数据byte gzip[] = bout2.toByteArray();System.out.println("压缩大小:" + gzip.length);response.setHeader("content-encoding", "gzip");response.setContentLength(gzip.length);response.getOutputStream().write(gzip);}/*** @Method: getHttpServletResponseProxy* @Description: 获取HttpServletResponse对象的代理对象* @Anthor:孤傲苍狼** @param response* @param bout* @param pw* @return HttpServletResponse对象的代理对象*/ private ServletResponse getHttpServletResponseProxy(final HttpServletResponse response,final ByteArrayOutputStream bout, final PrintWriter pw) {return (ServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(), response.getClass().getInterfaces(), new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {if(method.getName().equals("getWriter")){return pw; }else if(method.getName().equals("getOutputStream")){return new MyServletOutputStream(bout);}else{return method.invoke(response, args);}}});}@Overridepublic void destroy() {}class MyServletOutputStream extends ServletOutputStream{private ByteArrayOutputStream  bout = null;public MyServletOutputStream(ByteArrayOutputStream  bout){this.bout = bout;}@Overridepublic void write(int b) throws IOException {bout.write(b);}}
}

  在web.xml中注册上述的GzipFilter

<filter><description>配置压缩过滤器</description><filter-name>GzipFilter</filter-name><filter-class>me.gacl.web.filter.GzipFilter</filter-class></filter><!--jsp文件的输出的内容都经过压缩过滤器压缩后才输出 --><filter-mapping><filter-name>GzipFilter</filter-name><url-pattern>*.jsp</url-pattern><!-- 配置过滤器的拦截方式--><!-- 对于在Servlet中通过request.getRequestDispatcher("jsp页面路径").forward(request, response) 方式访问的Jsp页面的要进行拦截 --><dispatcher>FORWARD</dispatcher><!--对于直接以URL方式访问的jsp页面进行拦截,过滤器的拦截方式默认就是REQUEST--><dispatcher>REQUEST</dispatcher></filter-mapping><!--js文件的输出的内容都经过压缩过滤器压缩后才输出 --><filter-mapping><filter-name>GzipFilter</filter-name><url-pattern>*.js</url-pattern></filter-mapping><!--css文件的输出的内容都经过压缩过滤器压缩后才输出 --><filter-mapping><filter-name>GzipFilter</filter-name><url-pattern>*.css</url-pattern></filter-mapping><!--html文件的输出的内容都经过压缩过滤器压缩后才输出 --><filter-mapping><filter-name>GzipFilter</filter-name><url-pattern>*.html</url-pattern></filter-mapping>

  GzipFilter过滤器会将*.jsp,*.js,*.css,*.html这些文件里面的文本内容都经过压缩后再输出到客户端显示。

转载于:https://my.oschina.net/HerrySun/blog/656559

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

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

相关文章

【ArcGIS微课1000例】0006:创建随机点(Create Random Points)

问题描述 在一个给定的范围内,根据随机位置,生成指定数量的随机点。生成的随机点通常用来提取每个点对应的NDVI,高程,气温等值。 ArcGIS创建随机点 创建指定数量的随机点要素。可以在范围窗口中、面要素内、点要素上或线要素沿线生成随机点。 工具介绍:

[转]《吐血整理》系列-顶级程序员工具集

你知道的越多&#xff0c;你不知道的越多 点赞再看&#xff0c;养成习惯 GitHub上已经开源 https://github.com/JavaFamily 有一线大厂面试点脑图、个人联系方式&#xff0c;欢迎Star和指教 前言 这期是被人才群交流里&#xff0c;还有很多之前网友评论强行顶出来的一期&#x…

跟我做⼀个高德地图的 iOS / Android MAUI 控件(前言)

Microsoft Build 2022 ⼤会上正式发布了 .NET MAUI , 对于 .NET 开发者可以⽤ C# 完成跨平台的前端应⽤开发。对⽐起 MAUI 的前身 Xamarin , MAUI 除了可以⽤传统的原⽣开发模式外&#xff0c;还⽀持了 Blazor 的混合式开发。这也让更多⽅向的开发⼈员能进⼊到跨平台的应⽤开发…

Valid Number

Valid Number 题解 题目描述 即判断某个字符串是否合法的数字表达式。如&#xff1a; 2e10&#xff0c;合法。 75.0.&#xff0c;非法。 0e&#xff0c;非法。 0.1 &#xff0c;合法。题解 基于规则与状态判断。可利用二维数组模拟状态转移图&#xff0c;又或是利用变量记录状…

java.util.ListIterator

列表迭代器并不持有当前元素的引用&#xff0c;其持有的游标是位于列表连个元素之间。可以通过调用next()或者previous()返回列表中的元素。一个拥有n个元素的列表拥有n1个游标位置&#xff0c;示意图如下&#xff1a; 注意&#xff1a;remove和 set(Object)方法并不是以迭代器…

C语言试题164之求定积分

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款刷算法、笔试、面经、拿大公司offer神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:利用梯形…

spring boot微服务通用部署启动脚本

2019独角兽企业重金招聘Python工程师标准>>> 通用springboot微服务启动、停止脚本。 #!/bin/bash # # chkconfig: - 20 80 # description: Starts and stops the App. # author:vakingeENVdev RUNNING_USERvakinge ADATEdate %Y%m%d%H%M%S APP_NAMEpassport-serve…

VB实现6大排序算法---动态过程展示(建议收藏)

VB实现6大排序算法&#xff1a;插入排序、基数排序、快速排序、希尔排序、选择排序、归并排序。可以随机生成指定个数的数据&#xff0c;显示排序过程&#xff0c;给出排序结果&#xff0c;计算排序算法消耗的时间。 生成随机数&#xff1a; 排序结果&#xff1a; 插入排序&…

C# 实现 Actor并发模型 (案例版)

啥是Actor模型Actor (英语翻译 演员) 这个概念要回溯到面向对象程序设计的本身上来&#xff0c;更偏向于现实世界&#xff0c;现实世界就是由单个个体&#xff08;人&#xff09;与其他个体或(人&#xff09;通讯&#xff08;消息&#xff09;组成的现实世界&#xff0c;所以&a…

超详细C语言版数据结构:图的深度优先遍历(推荐收藏)

文章目录一、邻接矩阵存储图的深度优先遍历过程分析二、结果分析三、C语言编程实现图的深度优先遍历四、图的遍历及其应用一、邻接矩阵存储图的深度优先遍历过程分析 对图1这样的无向图&#xff0c;要写成邻接矩阵&#xff0c;则就是下面的式子&#xff1a; 一般要计算这样的问…

Navicat Premium 64 bit 12.1.25

Navicat Premium可让你以单一程序同時连接到 MySQL、MariaDB、SQL Server、SQLite、Oracle 和 PostgreSQL 数据库&#xff0c;是一个可多重连接的数据库管理工具&#xff0c;它让管理不同类型的数据库更加方便。 官方下载地址&#xff1a;https://www.navicat.com.cn/download/…

[JMX一步步来] 7、用JDK5.0的JConsole来连接MBean

前面所有看效果都是通过Html网页来看的。JDK5.0自带了一个jmx客户端&#xff0c;叫jconsole&#xff0c;位于c:\jdk\bin\jconsole.exe。我们来用用这个客户端来连接Mbean Server。一、vm参数方式1、还是用第一篇的那个HelloAgent&#xff0c;修改HelloAgent&#xff0c;将第一句…

记一次 .NET 某新能源系统 线程疯涨 分析

一&#xff1a;背景 1. 讲故事前段时间收到一个朋友的求助&#xff0c;说他的程序线程数疯涨&#xff0c;寻求如何解决。等我分析完之后&#xff0c;我觉得这个问题很有代表性&#xff0c;所以拿出来和大家分享下&#xff0c;还是上老工具 WinDbg。二&#xff1a;WinDbg 分析 1…

[转]ES7、ES8、ES9、ES10新特性大盘点

ES7、ES8、ES9、ES10新特性大盘点 本文转自&#xff1a;https://mp.weixin.qq.com/s/8bov6788ivV0sHzmwrn5lw 以下文章来源于前端工匠 &#xff0c;作者浪里行舟君 前端工匠 我是浪里行舟&#xff0c;Github博客4000star作者&#xff0c;致力于打造一系列能够帮助初中级工程师…

热榜!!!数据结构与算法:C语言版---数组与稀疏矩阵---强势来袭!

数组是各种计算机语言中经常使用到的重要数据结构&#xff0c;一般的说&#xff1a;在内存中申请一片连续地址的存储空间、存储这些数、就称为数组。 在C语言中&#xff0c;申请连续的存储空间是很容易的事情&#xff0c;但难在多维数组的组织、以及数组数据的压缩上&#xff…

第一声问候

前一篇《Emacs 是一台计算机》理解了 Emacs 身为计算机的本质之后&#xff0c;在 Emacs 里编程就顺理成章了。不过&#xff0c;在此之前&#xff0c;还需要略微介绍一下 Emacs 最基本的操作。 系统的不一致&#xff0c;令人有点烦躁 现在&#xff0c;也可以坦然地说&#xff0c…

破解支付宝AR红包

支付宝新出的AR红包没多久&#xff0c;就有人破解了&#xff0c;大致原理是将上面的像素条遮挡下面的黑条&#xff0c;基本上得到模糊的图就可以扫到红包。不过现在大多是ps解决&#xff0c;那得有多麻烦啊&#xff0c;所以我用java写了一个&#xff0c;效果还不错。 先截屏&am…

在 Windows 上搭建配置 Jenkins 然后编译打包 VS 项目

在 Windows 上搭建配置 Jenkins 然后编译打包 VS 项目独立观察员 2022 年 7 月 6 日一、安装1、下载并安装 JRE &#xff08;Java 运行环境&#xff09;。2、下载 Windows 版本的 Jenkins 安装包并安装。3、安装 Visual Studio&#xff0c;以供编译项目使用。4、安装 Advanced …

【ArcGIS微课1000例】0007:基于数字高程模型DEM生成剖面线、剖面图

文章目录 效果预览数据分析工具介绍生成过程剖面图编辑保存、导出剖面图实验数据下载效果预览 数据分析 本实例使用到的原始数据为案例提供的规则格网DEM

[转]javaandroid线程池

java多线程-概念&创建启动&中断&守护线程&优先级&线程状态&#xff08;多线程编程之一&#xff09;java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()&#xff08;多线程编程之二&#xff09;java&android线程池-Exe…