Java 动态代理,invoke() 自动调用原理,invoke() 参数

2023-10-26

Java 动态代理,invoke() 自动调用原理,invoke() 参数

本文介绍了静态代理和动态代理的概念,并且用代码、注释、图示和源码的方式来分析动态代理原理和invoke()自动调用原理。


学习动态代理,先从静态代理入手

静态代理

假如现在我们面临一个需求,把一个项目中所有访问数据库的方法都记录日志。最直接的方法是修改所有代码,在每个方法里面都加入写日志代码:

public class Dao {
	User findUserbyId(int id) {
		// 业务代码
		xxx;
		// 加入写日志代码
		xxx;
	}
	
}

但是这样工作量会很大,并且模块之间是耦合的,比如下次的需求是修改记录日志的内容,那么又要去修改所有业务代码,显然这种方法是不可取的。

如果不可以修改业务代码呢?

很容易就想到静态代理,写代理类对业务代码进行调用,我们用老师教学生举例子:

/**
* 老师接口,老师可以教学生
*/
public interface Teacher { 
    void teach();
}
/**
* 老师接口的实现类,具体实现 teach() 方法
*/
public class RealTeacher implements Teacher {
    @Override
    public void teach() {
        System.out.println("I am a teacher, I am teaching!");
    }
}
/**
* 老师代理对象,增强 teach() 方法
*/
public class TeacherProxy implements Teacher {
    Teacher teacher = new RealTeacher();
    @Override
    public void teach() {
    	// 这里 dosomething() 可以实现一些代理类的功能
    	dosomething();
    	// 这里执行 RealTeacher 的 teach() 方法
    	teacher.teach();
        dosomething();
    }
}
/**
* 测试代理类
*/
public class ProxyTest {
    public static void main(String args[]) {
    	Teacher teacher = new TeacherProxy();
    	// 这里执行代理类的 teach() 方法
    	teacher.teach();
    }
}

用图示表示上面静态代理的代码,可以描述为:

从图片和代码可以看出,这里只是用一个新对象去包含原来的 RealTeacher 对象,看似多此一举,但是确实一个不改变原来的代码,对方法进行增强的好办法。但是,如果我们要增强很多方法,比如文章开头的例子,需要对所有访问数据库的方法添加日志记录,如果用静态代理,要为每一个对象编写代理累,代码量十分庞大,也难以维护。

动态代理

既然为每一个需要代理的对象(下文通称为目标对象)都编写相应的代理类很麻烦,那么能不能不写死代理对象和目标对象,只写一个代理对象就可以使用不同的目标对象呢?
答案是可以的,就是用动态代理。动态代理的代理对象不依赖于目标对象,不和目标对象耦合。其原理是把目标对象的类型信息(比如接口)作为参数,利用 Java 支持的反射来创建代理对象,这样,就解除了代理对象和目标对象的耦合,一个代理对象可以适用一些列的目标对象。用图表示为:
在这里插入图片描述
如上图所示,目标对象作为一个参数,动态代理得到这个参数之后分成三步走:

  1. 获得目标对象的接口信息和类加载器,然后根据这两个信息来反射得到代理类的 Class
  2. 获得目标对象的 Class
  3. 根据1 2两步获得的接口,代理类 Class,目标类 Class 实例化一个代理对象

这样, 就创建了一个代理对象。从图中可以看出,动态代理并没有和目标对象绑定,而是把目标对象作为一个参数。

JDK 提供了 java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类来实现上述反射等功能,其中 java.lang.reflect.InvovationHandler 接口用于绑定目标对象需要增强的方法,java.lang.reflect.Proxy 提供静态方法 NewProxyInstance() 用于创建一个代理类实例,这样,这个代理类实习就被创建出来并且通过嵌入 InvocationHandler 绑定了目标类的方法。
上面的静态代理代码的例子改成动态代理:

/**
 * 老师接口,老师可以教学生
 */
public interface Teacher {
    void teach();
}

/**
 * 老师接口的实现类,具体实现 teach() 方法
 */
public class RealTeacher implements Teacher {
    @Override
    public void teach() {
        // 老师正在教书
        System.out.println("I am a teacher, I am teaching!");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 代理类,根据接口等信息动态地创建代理对象,其中 MyProxy 是 InvocationHandler 的实现类,用于绑定方法
 */
public class MyProxy implements InvocationHandler {
    // tar用于接收目标类的参数
    private Object tar;

    // 绑定目标类,根据目标类的类加载器和接口创建代理对象,并返回
    public Object bind(Object target) {
        this.tar = target;
        // 注意:此处代码返回代理类
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(), 
        tar.getClass().getInterfaces(), this);
    }
    // invoke() 方法用于方法的增强
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        // 执行一些方法
        System.out.println("Do something before");

        // 目标类的方法执行,这里实际上是执行目标对象的方法,
        // 也就是 bind(Object target)参数 object target 的方法
        result = method.invoke(tar, args);

        System.out.println("Do something after");
        return result;
    }
}


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) throws Throwable {
        MyProxy proxy = new MyProxy();

        // 传入目标对象,进行绑定
        Teacher teacher = (Teacher)proxy.bind(new RealTeacher());

        // 执行代理对象的方法
        teacher.teach();
    }
}

测试函数的输出应该为:

Do something before
I am a teacher, I am teaching!
Do something after

改写成内部类的方式可以更清楚的看到:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) throws Throwable {
        // 这里能清楚地看到,目标对象 RealTeacher 是一个纯粹的参数
        Teacher teacher = (Teacher)getProxy(new RealTeacher());
        // teacher 是接口 Teacher 的一个实现类,
        // 完全从多态的角度也能想到执行的实际上是 RealTeacher 的 teach() 方法
        teacher.teach();
    }
    public static Object getProxy(Object target) throws Throwable{

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = null;
                        System.out.println("Do something before");
                        result = method.invoke(target, args);
                        System.out.println("Do something after");
                        return result;
                    }
        });
    }
}

此源代码在 GitHub 上。
目标对象 RealTeacher 可以看成是一个纯粹的参数,不和代理类耦合。
在应用的时候,可以把具体实现过程忽略,把

Teacher teacher = (Teacher)getProxy(new RealTeacher());

看成一个黑箱,它输入一个目标类作为参数,返回一个实现了 Teacher 接口的代理类。到此为止,我们成功使用了动态代理,在没有和目标类 RealTeacher 绑定的情况下,创建了一个代理类,增强了 teach() 方法。

进一步深究代理类 teacher,invoke()

为了进一步探究生成的代理类 teacher 到底是什么一个情况,我们输出 teach 的一些类型信息:

    public static void main(String[] args) throws Throwable {
        // 这里能清楚地看到,目标对象 RealTeacher 是一个纯粹的参数
        Teacher teacher = (Teacher)getProxy(new RealTeacher());
        // teacher 是接口 Teacher 的一个实现类,
        // 完全从多态的角度也能想到执行的实际上是 RealTeacher 的 teach() 方法
        teacher.teach();

        System.out.println(teacher.getClass().getSuperclass());//输出是class java.lang.reflect.Proxy

        Class<?>[] interfaces = teacher.getClass().getInterfaces();

        for(Class<?> i : interfaces){
            System.out.println(i);// 输出是interface Teacher
        }

        Method[] methods = teacher.getClass().getDeclaredMethods();

        for (Method method : methods) {
            System.out.println(method);
            // 输出是:
            // public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object)
            // public final java.lang.String com.sun.proxy.$Proxy0.toString()
            // public final int com.sun.proxy.$Proxy0.hashCode()
            // public final void com.sun.proxy.$Proxy0.teach() 

        }
    }

由上述输出可以发现,

Teacher teacher = (Teacher)getProxy(new RealTeacher());

创建的代理类 teacher 实际是名字是 $Proxy0,它父类 Proxy,实现了 Teacher 接口,实现了 teach() 方法,所以代码

teacher.teach();

理所当然可以执行。

但是,我们知道代码 teacher.teach(); 最终执行了invoke()方法,那么这个teach()方法到底怎么和invoke()有关联的呢?

我们打开 teach 的方法 Proxy.newProxyInstance()源码的注释,关键的是这几行:

 * Returns a proxy instance for the specified interfaces
 * that dispatches method invocations to the specified invocation
 * handler.

@param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces

再看 Proxy 类的注释:

* {@code Proxy} provides static methods for creating objects that act like instances
 * of interfaces but allow for customized method invocation.
 * To create a proxy instance for some interface {@code Foo}:
 * <pre>{@code
 *     InvocationHandler handler = new MyInvocationHandler(...);
 *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
 *                                          new Class<?>[] { Foo.class },
 *                                          handler);
 * }</pre>
 *
 * <p>
 * A <em>proxy class</em> is a class created at runtime that implements a specified
 * list of interfaces, known as <em>proxy interfaces</em>. A <em>proxy instance</em>
 * is an instance of a proxy class.
 *
 * Each proxy instance has an associated <i>invocation handler</i>
 * object, which implements the interface {@link InvocationHandler}.
 * A method invocation on a proxy instance through one of its proxy
 * interfaces will be dispatched to the {@link InvocationHandler#invoke
 * invoke} method of the instance's invocation handler, passing the proxy
 * instance, a {@code java.lang.reflect.Method} object identifying
 * the method that was invoked, and an array of type {@code Object}
 * containing the arguments.  The invocation handler processes the
 * encoded method invocation as appropriate and the result that it
 * returns will be returned as the result of the method invocation on
 * the proxy instance.
 *

由注释发现,Proxy.newProxyInstance()方法返回一个代理对象的实例,这个实例是和一个特殊的 InvocationHandler 相关的,再回看我们写的代码:
在这里插入图片描述
我们实例化的匿名内部类 InvocationHandler 正是有 invoke() 方法,所以刚才的问题:

那么这个teach()方法到底怎么和invoke()有关联的呢?

是因为代理对象实例 teacher 的父类是 Proxy,由 Proxy 去和我们实例化的匿名内部类 InvocationHandler 去关联

再看实例对象 teacher(也就是 $Proxy0 )的反编译代码:(此代码来自这里

public final class $Proxy0 extends Proxy implements Subject {  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
  
    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
                    new Class[] { Class.forName("java.lang.Object") });  
  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                    new Class[0]);  
  
            m3 = Class.forName("***.RealSubject").getMethod("request",  
                    new Class[0]);  
  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
                    new Class[0]);  
  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    } //static  
  
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  
    }  
  
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final void teach() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null);  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
}  

也验证了当执行 teacher.teach() 的时候,也就是执行 $Proxy0.teach() 的时候,会执行 super.h.invoke(),也就是执行父类 Proxy 的 invoke(),而父类 Proxy 是和 InvocationHandler 是关联的,总结为:

teacher.teach() --> $Proxy0.teach() --> super.h.invoke() --> proxy.invoke() --> invocationHandler.invoke()

图示可以表示为:
在这里插入图片描述

invoke() 的参数

从代码可以看出,invoke() 方法有三个参数:

  • Object proxy
  • Method method
  • Object[] args

我们在 invoke() 中输出 proxy 的名字:

return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    	// 输出proxy名字
                        System.out.println(proxy.getClass().getName());
                        
                        Object result = null;
                        System.out.println("Do something before1");
                        result = method.invoke(target, args);
                        System.out.println("Do something after1");
                        return result;
                    }
        });

输出是:
在这里插入图片描述
上文说代理类名字是 $Proxy0,所以实际上 proxy 参数就是代指反射创建的代理类 $Proxy0,之所以不用 this,因为 this 代表的是 InvocationHandler() 这个匿名内部类的实例。

同样的,我们看 $Proxy0 的反编译代码:
在这里插入图片描述
这个代码中的this就是 $Proxy0 对象本身,也是作为 invoke() 的第一个参数,也就是 proxy 进行参数传递。所以也能得到 proxy 参数就是代指反射创建的代理类 $Proxy0 的结论。

对于第二个参数 method,我们看 Method 的注释:

 * A {@code Method} provides information about, and access to, a single method
 * on a class or interface.  The reflected method may be a class method
 * or an instance method (including an abstract method).

可以看出第二个参数 method 用于绑定的目标类的方法

第三个参数是方法的参数

总结

代理模式是一种不改变源代码对方法进行增强的好方法,但是静态代理代理类和目标类是绑定耦合的。

动态代理的特点是:

  • 利用目标类的接口信息,通过反射创建代理类
  • 可以把代理类固定下来,不因为业务代码量庞大而复杂,便于扩展、修改和维护。
  • 方便实现 RPC 和 AOP
  • 源码难以理解
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 动态代理,invoke() 自动调用原理,invoke() 参数 的相关文章

  • JNA - EnumProcessModules() 未返回所有 DLL?

    我试图从游戏中读取坐标 当我在通过 OpenProcess 接收的 HANDLE 上使用 ReadProcessMemory 以及我在 CheatEngine 中找到的内存时 效果非常好 例如 如果我知道正在运行的进程中的浮点值是0x5AB
  • 如何使用retrofit2动态设置超时?

    public class Router private static Retrofit retrofit null public Retrofit getRetrofit if retrofit null OkHttpClient clie
  • jvm中本机代码如何转换为机器代码[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我读过一些文章说 jvm将字节码转换为机器码 jvm将字节码转换为本机代码 jvm 将字节码转换为系统调用 系统调用又由操作系统与硬件
  • 如何在Spring Boot中初始化一次MongoClient并使用它的方法?

    您好 我正在尝试导出MongoClient在 Spring Boot 中成功连接后 我尝试在其他文件中使用它 这样我就不必每次需要在 MongoDB 数据库中进行更改时都调用该连接 连接非常简单 但目标是将应用程序连接到我的数据库一次 然后
  • Glassfish:在部署期间修改 EAR 的部署描述符

    经过几天的搜索 尝试和摇头 我将这个问题发布到 SO 尽管它seems已经得到答复 这是场景 我有一个 EAR 应用程序 目前 包含一个 WAR 和一个 EJB 模块 EJB 模块使用 JPA persistence xml 并且一些无状态
  • 初始堆大小无效。无法创建Java虚拟机

    我遇到了下一个问题 我尝试通过startup bat手动启动Tomcat 但似乎没有显示任何结果 然后我尝试运行shutdown bat 控制台显示如下 D apache tomcat 7 0 35 bin gt startup bat U
  • EL 通过 Scriptlet

    在 JSP 中使用 EL 相对于 scriptlet 的优势是什么 EL 被认为是无脚本语言 EL 使 JSP 免受容易出错原始 Java 代码并强制您根据 MVC 思想编写 JSP EL 或像 JSTL 这样的标签库 不可能实现的任何事情
  • 从字符串生成密钥?

    我需要从字符串生成一个密钥 以便我始终可以从同一字符串创建相同的密钥 具体来说是一个Key对象 这样我就可以用它来创建Cipher进而创建SealedObject 这在 Java 中可行吗 我应该考虑什么类 方法组合才能做到这一点 对于 A
  • c和java语言中的换行符

    现在行分隔符取决于系统 但在 C 程序中我使用 n 作为行分隔符 无论我在 Windows 还是 Linux 中运行它都可以正常工作 为什么 在java中 我们必须使用 n 因为它与系统相关 那么为什么我们在c中使用 n 作为新行 而不管我
  • 我需要一个字数统计程序[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我需要弄清
  • org.apache.commons.codec.digest.Md5Crypt.md5Crypt 函数。 linux下出现异常,windows下正常

    我们正在使用commons codec加密密码 使用org apache commons codec digest Md5Crypt md5Crypt功能 在Windows环境下工作正常 但在CentOS上却抛出异常 我们有3台centOS
  • java中日期转换dd-MMM-yyyy到dd-MM-yyyy

    在Java中将23 Mar 2011转换为23 03 2011的最简单方法是什么 感谢大家 这似乎解决了这个问题 try Calendar cal Calendar getInstance cal setTime new SimpleDat
  • JFrame Glasspane 也优于 JDialog,但不应该

    我有一个带有 Glasspane 的 JFrame 未装饰 该框架打开一个 JDialog 也未装饰 也有一个 glassPane 并隐藏自身 setVisible false Glasspanes 通过 setGlassPane 设置 对
  • 春季MVC。方法参数字段的默认值

    我有一个带有方法测试的简单控制器 RequestMapping produces application json ResponseBody public HttpEntity
  • 如何列出hadoop hdfs中目录及其子目录中的所有文件

    我在 hdfs 中有一个文件夹 其中有两个子文件夹 每个子文件夹大约有 30 个子文件夹 最后 每个子文件夹都包含 xml 文件 我想列出所有 xml 文件 仅给出主文件夹的路径 在本地我可以这样做apache commons io 的 h
  • Java 中更高级的泛型

    假设我有以下课程 public class FixExpr Expr
  • while 之后无法访问的语句[重复]

    这个问题在这里已经有答案了 我只是修改代码 在以下代码中出现错误 int x 1 System out println x x while true x System out println x x 错误在最后一行 我可以知道错误 错误 无
  • Spring Transactional 减慢了整个过程

    我正在尝试分析我有两堂课的情况 其中一个类是 ProcessImpl 它是起点并在内部调用其他子事务 我不知道出了什么问题 processImpl正在导入一些东西并将相关数据写入数据库 Specs Spring orm版本 3 2 18 发
  • Lucene/Hibernate 搜索锁定异常

    我使用 Hibernate Search 在 Web 应用程序上索引和全文搜索项目 没有问题 来自我的 pom xml
  • 如何创建具有同等时间元素的 JavaFX 转换?

    我正在尝试 JavaFX 和动画 尤其是PathTransition 我正在创建一个简单的程序 使球 弹跳 而不使用QuadCurveTo班级 到目前为止 这是我的代码 Ellipse ball new Ellipse 375 250 10

随机推荐

  • 使用 docker 容器化 Go-Gin 应用程序!

    文章目录 介绍 先决条件 构建 Gin 框架应用程序 创建 Dockerfile 构建 Docker 镜像 运行 Docker 容器 结论 使用 docker 容器化 Go Gin 应用程序 马赫什瓦尔 利加德的照片 马赫什瓦尔 利加德 1
  • html生成jsessionid,H5 APP 使用 JSESSIONID 保持会话登录

    前言 这段时间给电影网站加了收费在线观看的权限 由于之前的 APP 没有添加登录模块 所以现在必须得添加上了 APP 基于 H5 MUI 开发 在实现的过程中真的是碰得焦头烂额的 过程 H5 开发 APP 无非就是利用 WebView 操作
  • 论文学习 Deep Adversarial Subspace Clustering

    deep adversarial subspace clustering 前提知识 1 子空间聚类 2 LRR 低秩表示 摘要 introduction Method 原理 生成器 操作步骤 G的损失函数 判别器 参数的学习 损失函数 de
  • MediaSource 缓存

    wfs js MediaSource 缓存 window mediasource
  • 线程池的优点

    线程池的优点 普通线程 线程池 普通线程 通常我们使用new Thread 新建线程 但是这样新建的线程会缺乏统一管理 会导致线程之前存在竞争 从而过多占用系统的资源导致效率变低 而且这种线程功能比较单一 相较于线程池无法定时 定期执行线程
  • 操作系统内存管理

    内存管理 一级目录 二级目录 三级目录 虚拟内存空间 分段内存 段选择符 段描述符 分页内存 逻辑地址 虚拟地址和线性地址的关系 分页管理 概念 页式管理 说明 步骤 硬件高速缓存 内存管理的结构体 总览 struct page struc
  • 7.26作业

    百钱买百鸡 include
  • Leetcode 53最大子序和

    最大子序和 给定一个整数数组 nums 找到一个具有最大和的连续子数组 子数组最少包含一个元素 返回其最大和 示例 输入 2 1 3 4 1 2 1 5 4 输出 6 解释 连续子数组 4 1 2 1 的和最大 为 6 进阶 如果你已经实现
  • Backtrader 获得上个交易日的日期

    在策略类backtrader Strategy中使用 self datetime date 1 即可得到上个交易日 但是不能得到下个交易日的日期 因为目前还没有循环过这个时间
  • filebrowser文件管理系统详细使用说明

    1 所有可用参数 a address string 要侦听的地址 默认值为 127 0 0 1 b baseurl string 基础url cache dir string 文件缓存目录 如果为空则禁用 t cert string tls
  • Ubuntu双系统启动时卡死解决办法

    ubuntu双系统启动时卡死解决办法 在ubuntu16 04和18 04测试无误 问题描述 在安装完ubuntu双系统后 第一次启动ubuntu系统时 卡死在启动界面 或者黑屏 这大概都是由于显卡驱动的原因 具体不在这里阐述 通过以下方法
  • flink-cdc 实现oracle 实时同步到kudu

    其实网上也有很多相关话题的代码实现 但是发现有很多坑 在 腾讯官方文档中 有介绍 但是屏蔽了很多细节 我做了以下四点修改才能正常运行 1 前置条件 保证oracle中相关表开启了归档日志和补充日志 因为flink cdc基于debezium
  • IOS 多线程初探(二) - Operation Object

    上次简单介绍了使用NSThread来创建线程的方法 今天简单介绍使用Operation Object来创建线程 Operation Object简介 将要执行的任务 即函数 封装成操作对象NSOperation 并将对象放置到NSOpera
  • [C++STL] 严格弱序(less函数、小于号重载)

    前言 严格弱序 stick weak ordering 在以下场景会涉及到 对一个容器进行排序时 如使用std sort 使用有序关联容器时 如使用std set std map 使用std less时 重载 lt 操作符 小于 其中 st
  • Vue 中使用 v-for 展示不同的图片

    1 示例前提 展示一个数组对象数据 数组对象中没有图片字段 图片字段在本地保存 根据不同的id 下标 展示不同的图片 示例代码 template 中的代码
  • 数字图像处理扭曲效果——挤压效果

    挤压效果 挤压效果是将图像向内挤压 产生收缩变形 挤压效果的实现可以看成是数学极坐标的一种体现 将当前像素点 图像正中心点和过中心点的水平线这三要素画出一个极坐标 然后根据用户指定的挤压度 在当前点与中心点所连的直线上映射出一个像素点 最后
  • VulnHub-Tr0II

    一 信息收集 将靶机部署好之后改成NAT模式 扫描本网段发现目标ip 进一步探测ip 通过进一步的探测发现目标开启了21 22 80三个端口 先去80端口看一眼web服务 一张图没其它内容 扫一下目录看看 挨个访问也没有啥特殊的地方 考虑一
  • PropertyDescriptor获取非标准java bean属性的getter和setter时候的一个问题

    1 import java beans IntrospectionException 2 import java beans PropertyDescriptor 3 import java lang reflect InvocationT
  • 显著性水平对应的临界值_统计学问题 常有的显著性水平a 所对应的Z值是哪些...

    展开全部 z a 2 指的是标准正态分布的双侧临界值 z a 当然就是单侧临界值 a 阿尔法 指62616964757a686964616fe4b893e5b19e31333431356638的是显著水平 一般是0 05 0 01等 而95
  • Java 动态代理,invoke() 自动调用原理,invoke() 参数

    Java 动态代理 invoke 自动调用原理 invoke 参数 本文介绍了静态代理和动态代理的概念 并且用代码 注释 图示和源码的方式来分析动态代理原理和invoke 自动调用原理 学习动态代理 先从静态代理入手 静态代理 假如现在我们