java对象clone()方法

2023-11-17

java赋值是复制对象引用,如果我们想要得到一个对象的副本,使用赋值操作是无法达到目的的:

@Test
public void testassign(){
  Person p1=new Person();
  p1.setAge(31);
  p1.setName("Peter");

  Person p2=p1;
  System.out.println(p1==p2);//true
}

如果创建一个对象的新的副本,也就是说他们的初始状态完全一样,但以后可以改变各自的状态,而互不影响,就需要用到java中对象的复制,如原生的clone()方法。

如何进行对象克隆

Object对象有个clone()方法,实现了对象中各个属性的复制,但它的可见范围是protected的,所以实体类使用克隆的前提是:

① 实现Cloneable接口,这是一个标记接口,自身没有方法。 
② 覆盖clone()方法,可见性提升为public。

@Data
public class Person implements Cloneable {
    private String name;
    private Integer age;
    private Address address;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

@Test
public void testShallowCopy() throws Exception{
  Person p1=new Person();
  p1.setAge(31);
  p1.setName("Peter");

  Person p2=(Person) p1.clone();
  System.out.println(p1==p2);//false
  p2.setName("Jacky");
  System.out.println("p1="+p1);//p1=Person [name=Peter, age=31]
  System.out.println("p2="+p2);//p2=Person [name=Jacky, age=31]
}

该测试用例只有两个基本类型的成员,测试达到目的了。

事情貌似没有这么简单,为Person增加一个Address类的成员:

@Data
public class Address {
    private String type;
    private String value;
}

再来测试,问题来了。

@Test
public void testShallowCopy() throws Exception{
  Address address=new Address();
  address.setType("Home");
  address.setValue("北京");

  Person p1=new Person();
  p1.setAge(31);
  p1.setName("Peter");
  p1.setAddress(address);

  Person p2=(Person) p1.clone();
  System.out.println(p1==p2);//false

  p2.getAddress().setType("Office");
  System.out.println("p1="+p1);
  System.out.println("p2="+p2);
}

查看输出:

false
p1=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))

遇到了点麻烦,只修改了p2的地址类型,两个地址类型都变成了Office。

浅拷贝和深拷贝

前面实例中是浅拷贝和深拷贝的典型用例。

浅拷贝:被复制对象的所有值属性都含有与原来对象的相同,而所有的对象引用属性仍然指向原来的对象。

深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。

也就是说,一个默认的clone()方法实现机制,仍然是赋值。

如果一个被复制的属性都是基本类型,那么只需要实现当前类的cloneable机制就可以了,此为浅拷贝。

如果被复制对象的属性包含其他实体类对象引用,那么这些实体类对象都需要实现cloneable接口并覆盖clone()方法。

@Data
public class Address implements Cloneable {
    private String type;
    private String value;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

这样还不够,Person的clone()需要显式地clone其引用成员。

@Data
public class Person implements Cloneable {
    private String name;
    private Integer age;
    private Address address;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj=super.clone();
        Address a=((Person)obj).getAddress();
        ((Person)obj).setAddress((Address) a.clone());
        return obj;
    }
}

重新跑前面的测试用例:

false
p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))

clone方式深拷贝小结

① 如果有一个非原生成员,如自定义对象的成员,那么就需要:

  • 该成员实现Cloneable接口并覆盖clone()方法,不要忘记提升为public可见。
  • 同时,修改被复制类的clone()方法,增加成员的克隆逻辑。

② 如果被复制对象不是直接继承Object,中间还有其它继承层次,每一层super类都需要实现Cloneable接口并覆盖clone()方法。

与对象成员不同,继承关系中的clone不需要被复制类的clone()做多余的工作。

一句话来说,如果实现完整的深拷贝,需要被复制对象的继承链、引用链上的每一个对象都实现克隆机制。

前面的实例还可以接受,如果有N个对象成员,有M层继承关系,就会很麻烦。

利用序列化实现深拷贝

clone机制不是强类型的限制,比如实现了Cloneable并没有强制继承链上的对象也实现;也没有强制要求覆盖clone()方法。因此编码过程中比较容易忽略其中一个环节,对于复杂的项目排查就是困难了。

要寻找可靠的,简单的方法,序列化就是一种途径。

  • 被复制对象的继承链、引用链上的每一个对象都实现java.io.Serializable接口。这个比较简单,不需要实现任何方法,serialVersionID的要求不强制,对深拷贝来说没毛病。

  • 实现自己的deepClone方法,将this写入流,再读出来。俗称:冷冻-解冻。

@Data
public class Person implements Serializable {
    private String name;
    private Integer age;
    private Address address;
    public Person deepClone() {
        Person p2=null;
        Person p1=this;
        PipedOutputStream out=new PipedOutputStream();
        PipedInputStream in=new PipedInputStream();
        try {
            in.connect(out);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try(ObjectOutputStream bo=new ObjectOutputStream(out);
                ObjectInputStream bi=new ObjectInputStream(in);) {
            bo.writeObject(p1);
            p2=(Person) bi.readObject();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return p2;
    }
}

原型工厂类

为了便于测试,也节省篇幅,封装一个工厂类。

公平起见,避免某些工具库使用缓存机制,使用原型方式工厂。

public class PersonFactory{
    public static Person newPrototypeInstance(){
        Address address = new Address();
        address.setType("Home");
        address.setValue("北京");

        Person p1 = new Person();
        p1.setAddress(address);
        p1.setAge(31);
        p1.setName("Peter");
        return p1;
    }
}

利用Dozer拷贝对象

Dozer是一个Bean处理类库。

maven依赖

<dependency>
  <groupId>net.sf.dozer</groupId>
  <artifactId>dozer</artifactId>
  <version>5.5.1</version>
</dependency>

测试用例:

@Data
public class Person {
    private String name;
    private Integer age;
    private Address address;

    @Test
    public void testDozer() {
    Person p1=PersonFactory.newPrototypeInstance();
        Mapper mapper = new DozerBeanMapper();
        Person p2 = mapper.map(p1, Person.class);
        p2.getAddress().setType("Office");
        System.out.println("p1=" + p1);
        System.out.println("p2=" + p2);
    }
}

@Data
public class Address {
    private String type;
    private String value;
}

输出:

p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))

注意:在万次测试中dozer有一个很严重的问题,如果DozerBeanMapper对象在for循环中创建,效率(dozer:7358)降低近10倍。由于DozerBeanMapper是线程安全的,所以不应该每次都创建新的实例。可以自带的单例工厂DozerBeanMapperSingletonWrapper来创建mapper,或集成到spring中。

还有更暴力的,创建一个People类:

@Data
public class People {
    private String name;
    private String age;//这里已经不是Integer了
    private Address address;

    @Test
    public void testDozer() {
    Person p1=PersonFactory.newPrototypeInstance();
        Mapper mapper = new DozerBeanMapper();
        People p2 = mapper.map(p1, People.class);
        p2.getAddress().setType("Office");
        System.out.println("p1=" + p1);
        System.out.println("p2=" + p2);
    }
}

只要属性名相同,干~

继续蹂躏:

@Data
public class People {
    private String name;
    private String age;
    private Map<String,String> address;//��

    @Test
    public void testDozer() {
    Person p1=PersonFactory.newPrototypeInstance();
        Mapper mapper = new DozerBeanMapper();
        People p2 = mapper.map(p1, People.class);
        p2.getAddress().put("type", "Office");
        System.out.println("p1=" + p1);
        System.out.println("p2=" + p2);
    }
}

利用Commons-BeanUtils复制对象

maven依赖

<dependency>
  <groupId>commons-beanutils</groupId>
  <artifactId>commons-beanutils</artifactId>
  <version>1.9.3</version>
</dependency>

测试用例:

@Data
public class Person {
    private String name;
    private String age;
    private Address address;

    @Test
    public void testCommonsBeanUtils(){
    Person p1=PersonFactory.newPrototypeInstance();
        try {
            Person p2=(Person) BeanUtils.cloneBean(p1);
            System.out.println("p1=" + p1);
            p2.getAddress().setType("Office");
            System.out.println("p2=" + p2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

利用cglib复制对象

maven依赖:

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.2.4</version>
</dependency>

测试用例:

@Test
public void testCglib(){
  Person p1=PersonFactory.newPrototypeInstance();
  BeanCopier beanCopier=BeanCopier.create(Person.class, Person.class, false);
  Person p2=new Person();
  beanCopier.copy(p1, p2,null);
  p2.getAddress().setType("Office");
  System.out.println("p1=" + p1);
  System.out.println("p2=" + p2);
}

结果大跌眼镜,cglib这么牛x,居然是浅拷贝。不过cglib提供了扩展能力:

@Test
public void testCglib(){
  Person p1=PersonFactory.newPrototypeInstance();
  BeanCopier beanCopier=BeanCopier.create(Person.class, Person.class, true);
  Person p2=new Person();
  beanCopier.copy(p1, p2, new Converter(){
    @Override
    public Object convert(Object value, Class target, Object context) {
      if(target.isSynthetic()){
        BeanCopier.create(target, target, true).copy(value, value, this);
      }
      return value;
    }
  });
  p2.getAddress().setType("Office");
  System.out.println("p1=" + p1);
  System.out.println("p2=" + p2);
}

Orika复制对象

orika的作用不仅仅在于处理bean拷贝,更擅长各种类型之间的转换。

maven依赖:

<dependency>
  <groupId>ma.glasnost.orika</groupId>
  <artifactId>orika-core</artifactId>
  <version>1.5.0</version>
</dependency>
</dependencies>

测试用例:

@Test
public void testOrika() {
  MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

  mapperFactory.classMap(Person.class, Person.class)
  .byDefault()
  .register();
  ConverterFactory converterFactory = mapperFactory.getConverterFactory();
  MapperFacade mapper = mapperFactory.getMapperFacade();

  Person p1=PersonFactory.newPrototypeInstance();
  Person p2 = mapper.map(p1, Person.class);
  System.out.println("p1=" + p1);
  p2.getAddress().setType("Office");
  System.out.println("p2=" + p2);
}

Spring BeanUtils复制对象

给Spring个面子,貌似它不支持深拷贝。

Person p1=PersonFactory.newPrototypeInstance();
Person p2 = new Person();
Person p2 = (Person) BeanUtils.cloneBean(p1);
//BeanUtils.copyProperties(p2, p1);//这个更没戏

深拷贝性能对比

@Test
public void testBatchDozer(){
  Long start=System.currentTimeMillis();
  Mapper mapper = new DozerBeanMapper();
  for(int i=0;i<10000;i++){
    Person p1=PersonFactory.newPrototypeInstance();
    Person p2 = mapper.map(p1, Person.class);
  }
  System.out.println("dozer:"+(System.currentTimeMillis()-start));
  //dozer:721
}
@Test
public void testBatchBeanUtils(){
  Long start=System.currentTimeMillis();
  for(int i=0;i<10000;i++){
    Person p1=PersonFactory.newPrototypeInstance();
    try {
      Person p2=(Person) BeanUtils.cloneBean(p1);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  System.out.println("commons-beanutils:"+(System.currentTimeMillis()-start));
  //commons-beanutils:229
}
@Test
public void testBatchCglib(){
  Long start=System.currentTimeMillis();
  for(int i=0;i<10000;i++){
    Person p1=PersonFactory.newPrototypeInstance();
    BeanCopier beanCopier=BeanCopier.create(Person.class, Person.class, true);
    Person p2=new Person();
    beanCopier.copy(p1, p2, new Converter(){
      @Override
      public Object convert(Object value, Class target, Object context) {
        if(target.isSynthetic()){
          BeanCopier.create(target, target, true).copy(value, value, this);
        }
        return value;
      }
    });
  }
  System.out.println("cglib:"+(System.currentTimeMillis()-start));
  //cglib:133
}
@Test
public void testBatchSerial(){
  Long start=System.currentTimeMillis();
  for(int i=0;i<10000;i++){
    Person p1=PersonFactory.newPrototypeInstance();
    Person p2=p1.deepClone();
  }
  System.out.println("serializable:"+(System.currentTimeMillis()-start));
  //serializable:687
}
@Test
public void testBatchOrika() {
  MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

  mapperFactory.classMap(Person.class, Person.class)
  .field("name", "name")
  .byDefault()
  .register();
  ConverterFactory converterFactory = mapperFactory.getConverterFactory();
  MapperFacade mapper = mapperFactory.getMapperFacade();

  Long start=System.currentTimeMillis();
  for(int i=0;i<10000;i++){
    Person p1=PersonFactory.newPrototypeInstance();
    Person p2 = mapper.map(p1, Person.class);
  }
  System.out.println("orika:"+(System.currentTimeMillis()-start));
  //orika:83
}

@Test
public void testBatchClone(){
  Long start=System.currentTimeMillis();
  for(int i=0;i<10000;i++){
    Person p1=PersonFactory.newPrototypeInstance();
    try {
      Person p2=(Person) p1.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
  }
  System.out.println("clone:"+(System.currentTimeMillis()-start));
  //clone:8
}

(10k)性能比较:

//dozer:721
//commons-beanutils:229
//cglib:133
//serializable:687
//orika:83
//clone:8

深拷贝总结

原生的clone效率无疑是最高的,用脚趾头都能想到。

偶尔用一次,用哪个都问题都不大。

一般性能要求稍高的应用场景,cglib和orika完全可以接受。

另外一个考虑的因素,如果项目已经引入了某个依赖,就用那个依赖来做吧,没必要再引入一个第三方依赖。

转载自https://blog.csdn.net/54powerman/article/details/64920431?locationNum=6&fps=1

有想学云计算的朋友可以看看这篇https://blog.csdn.net/qq_33314107/article/details/90677795

下面是学习云计算的总纲目录

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java对象clone()方法 的相关文章

  • JDBC连接Access数据库的几种方式介绍

    接下来总结一下常用的几种连接方式 例如有如下的Access数据库student 表basic 以及6条记录 现在通过几种方式在Jsp中将他们的数据显示出来 如图所示 对于几种连接Access数据库的方式 基本上都是基于JDBC ODBC方式
  • 设计一个学生类 Student 包含姓名、成绩两个属性。定义一个无参的构造方法和一个接收两个参数的构造方法。

    请按照以下要求设计一个学生类 Student 并进行测试 要求如下 Student 类中包含姓名 成绩两个属性 分别给这两个属性定义两个方法 一个方法用于设置值 另一个方法用于获取值 Student 类中定义一个无参的构造方法和一个接收两个
  • Java编程--IO流(Ⅱ 字节流)

    Java编程 IO流 字节流 File类虽然可以操作文件 但是并不是操作文件的内容 若要进行文件内容的操作只能通过两种途径完成 字节流和字符流 若要进行输入及输出操作一般都会按照如下的步骤进行 以文件操作为例 1 通过File类定义一个要操
  • 通用Ajax设计

    利用Servlet和反射技术实现通用的Ajax调用设计 如下 一 调用规则 在JS代码 调用者只需按下面的规范 即可实现异步或同步java方法调用 在你的jsp或html页面中 导入通用异步调用方法文件 km js 自定义 然后写异步调用方
  • 动态代理 [用jdk实现]

    一 java 的jdk動態代理 用JDK實現的動態代理 被代理的對象必須實現一個接口才可以 其實現主是通過java lang reflect Proxy類和 java lang reflect InvocationHandler接口 二 本
  • SSL连接的JAVA实现

    SSL连接分为双向认证和单向认证 其中双向认证表示服务器和客户端都需要分别校验对方的身份 单向认证则只需要客户端校验服务器的身份 SSL的双向认证的流程如下图 从以上流程可见 要完成双向认证 服务器端和客户端都需要验证对方的证书 然后再进行
  • Java技术——内部类

    内部类 inner class 定义 在一个类中定义另外一个类 这个类就叫做内部类 优点 内部类可以让我们将逻辑上相关的一组类组织起来 并由外部类来控制内部类的可见性 当我们建立一个内部类时 其对象 就拥有了与外部类对象 之间的一种关系 这
  • Java集合大总结——Collection集合

    Collection集合的整理 1 List Set Queue Map四者的区别 集合底层数据结构梳理 2 关于集合的的选用 2 1 为什么使用集合 3 List接口 3 1 ArrayList 和 Array 数组 的区别 3 1 Li
  • 完整实现 - 通过 DelayQueue 实现延时任务

    一 DelayQueue 的应用原理 二 订单延时任务的实现 三 订单处理 四 优缺点 实现延时任务有很多的方法 网上关于延时任务的实现的文章已经不少了 比如 实现延时任务的 10 种方法等等 但是这些文章基本上都是将方法大概的列举一下 给
  • SpringBoot - 配置类的实现

    一 基本用法 1 基本介绍 Spring Boot 推荐使用 java 配置完全代替 XML 配置 java 配置是通过 Configration 和 Bean 注解实现的 二者作用如下 Configration 注解 声明当前类是一个配置
  • 【2021最新版】Java多线程&并发面试题总结(108道题含答案解析)

    文章目录 JAVA并发知识库 1 Java中实现多线程有几种方法 2 继承Thread类 3 实现Runnable接口 4 ExecutorService Callable Future有返回值线程 5 基于线程池的方式 6 4 种线程池
  • 输入第一个字符串A,输入第二个字符串B,统计B在A中出现的次数 abcabcabd abc

    public class strCount public static void main String args 定义字符串 String str abc String ss abcabcabc 定义返回的次数 int count 0 f
  • Java集合详解——TreeSet集合的介绍及其排序

    一 TreeSet集合的自动排序 TreeSet集合的继承结构图 1 TreeSet集合使用红黑树数据结构实现元素的排序和存储 底层实际上是一个TreeMap集合 2 Tree Map集合底层实际上是一个二叉树 3 放到TreeSet集合中
  • AQS同步组件-CountDownLatch解析和案例

    CountDownLatch原理 CountDownLatch是通过一个计数器来实现的 计数器的初始化值为线程的数量 每当一个线程完成了自己的任务后 计数器的值就相应得减1 当计数器到达0时 表示所有的线程都已完成任务 然后在闭锁上等待的线
  • 拓扑排序算法原理及Java代码实现

    一 拓扑排序的概念 对一个有向无环图 Directed Acyclic Graph简称DAG G进行拓扑排序 是将G中所有顶点排成一个线性序列 使得图中任意一对顶点u和v 若边
  • JAVA基础原理篇_1.1—— 关于JVM 、JDK以及 JRE

    目录 一 关于JVM JDK以及 JRE 1 JVM 2 JDK 3 JRE 二 为什么说 Java 语言 编译与解释并存 2 2 将高级编程语言按照程序的执行方式分为两种 2 2 Java的执行过程 2 3 所以为什么Java语言 编译与
  • 数据结构与算法【Java】02---链表

    前言 数据 data 结构 structure 是一门 研究组织数据方式的学科 有了编程语言也就有了数据结构 学好数据结构才可以编写出更加漂亮 更加有效率的代码 要学习好数据结构就要多多考虑如何将生活中遇到的问题 用程序去实现解决 程序 数
  • Tomcat中404/500 错误,自定义错误页面

    Tomcat中404 500 错误 自定义错误页面 当服务器出现404 500错误时候希望能够给用户友好的现实界面 只需要在项目的web xml中添加一些配置
  • 多态的实现

    多态 之前介绍过多态的概念就是基类引用派生类对象且和派生类有相同的同名覆盖函数 那么现在我们就具体讲讲怎么实现多态 类方法实现多态性有两种方法 1 方法重载 可以声明多个同名但参数个数 类型 和顺序不同的方法 编译时根据参数 个数 类型和顺
  • 纯java实现相片转素描

    1 实例演示图片转素描效果 首先我们来看一下具体的效果 在项目中添加依赖

随机推荐

  • 迪文串口屏TTL与主控板RS232电平信号转换方案

    一 TTL和RS232简述 串口 COM口是指的物理接口形式 硬件 按位 bit 发送和接收字节 而TTL RS 232是指的电平标准 电信号 TTL和RS232不同在于 电平表示的逻辑含义不同 1 TTL 逻辑高电平 1 3 3V或5V
  • (转)工业机器人用什么语言编程的?

    机器人的开发语言一般为C C C Builder VB VC等语言 主要取决于执行机构 伺服系统 的开发语言 而机器人编程分为示教 动作级机器人编程语言 任务级编程语言三个级别 机器人编程语言分为专用操作语言 如VAL语言 AL语言 SLI
  • Dynamic Web project,Jsp可正常访问,servlet出现404,刷新出现Http500,解决方式

    新手建立首个Dynamic Web project Jsp可正常访问 servlet出现404 刷新出现Http500 解决方式如下 Tips 关于配置servlet到web xml Servlet class 为pakagename se
  • PyTorch 的 Autograd详解

    点击蓝字 关注视学算法 作者丨xiaopl 知乎 来源丨https zhuanlan zhihu com p 69294347 编辑丨极市平台 PyTorch 作为一个深度学习平台 在深度学习任务中比 NumPy 这个科学计算库强在哪里呢
  • Go语言学习9-结构体类型

    结构体类型 引言 1 结构体 1 1 类型表示法 1 2 值表示法 1 3 属性和基本操作 附录 引言 书接上篇 我们了解了Go语言的接口类型 现在介绍Go语言的结构体类型 主要如下 1 结构体 结构体类型既可以包含若干个命名元素 又称字段
  • React从入门到精通二

    React从入门到精通之购物车案例 1 购物车需求说明 使用到的data list 2 项目code 1 购物车需求说明 list data展示到列表中 每个item的通过 按钮来控制购买的数据量 删除按钮可以删除当前的item Total
  • Request+超详细代码+视图分析(获取值)

    Request 1 request对象和response对象的原理 1 request和response对象是由服务器创建的 我们来使用它们 2 request对象是来获取请求消息 response对象是来设置响应消息 2 request对
  • constrain用法_constrain是什么意思_constrain的用法

    constrain的音标 英 k n stre n 美 k n stre n constrain的用法 v 强迫 强制 迫使 限制 限定 约束 第三人称单数 constrains 现在分词 constraining 过去式 constrai
  • Numpy学习笔记

    基于Wes McKinney的Python for Data Analysis第四章NumPy Basics Arrays and Vectorized Computation整理代码得来 最近在自学Python 感觉还是要敲一下的 又懒得
  • ChatGPT的评估指标有哪些?微调与上下文学习是否存在相似性?

    NLP 分很多的任务 不同的任务有不同的指标来度量模型质量 比如AUC Precision Recall是分类模型的度量指标 ChatGPT可以看作一个生成式语言模型 简单说就是给它输入一段文字 它会输出另一段文字 当然输出和输入之间是有关
  • 关于ArithmeticException 异常捕获(double类型的数据除于0为什么是无穷大?)

    关于ArithmeticException 异常捕获 double类型的数据除于0为什么是无穷大 在做实验编写应用程序 从命令行中输入表示两个小数的参数的字符串 求它们的商 要求程序捕获NumberFormatException异常和Ari
  • 测试用例管理工具SynapseRT(jira插件)的具体使用(一)

    话说我们测试团队使用Zephyr进行测试用例管理一段时间后 得到大家的认可 反馈还不错 但我还是觉得它功能太单一 缺点较多 例如提供信息较少 无法记录和跟踪需求 管理人员无法直观了解测试进度等等 为了解决这些问题 我找到了SnapseRT插
  • 基于DVWA的文件上传漏洞测试

    目录 DVWA Low Medium DVWA Low DVWA Security的 low 级别可以直接上传 一句话 木马 1 1 编写测试木马 1 2 没有后缀过滤直接上传 1 3回显上传路径 直接访问即可 http localhost
  • 算法 - 快速排序(C#)

    csharp view plain copy print
  • 分治法 ( Divide And Conquer ) 详解

    文章目录 引言 分治法的范式 递归式 求解递归式的三种方法 代入法 递归树法 主方法 引言 在这篇 blog 中 我首先会介绍一下分治法的范式 接着给出它的递归式通式 最后我会介绍三种方法 代入法 递归树 和主方法 求解递归式 分治法的范式
  • 小程序技术原理分析

    小程序技术原理分析 背景 小程序诞生的技术背景 小程序与普通网页开发的区别 宿主环境 执行环境 小程序架构 一 技术选型 二 双线程模型 三 双线程通信 四 小程序的基础库 五 小程序运行时 运行机制 更新机制 六 性能优化 总结 背景 随
  • 懒加载、热加载(开发者模式)、热部署、预加载、热更新

    热部署 直接重新加载整个应用 生产环境 清空内存重新打包 重新解压war包 热加载 在运行时重新加载class 开发环境 基于字节码的更改 不释放内存开发可用 上线不可用 热加载不重启tomcat 不重新打包 懒加载 延迟加载 实现方法 先
  • 页式存储管理方式

    优点 分页存储管理解决了 内存碎片 问题 提高了资源的利用率 页式存储管理方式的实现思路 将作业分页 物理空间分块 块大小 页大小 将作业的每一页依次装入到物理空间中的块中执行 不要求装入连续的物理块 当所有页全部装入物理块后 才可以运行
  • 华为OD机试真题-核酸检测人员安排【2023Q1】【JAVA、Python、C++】

    题目描述 在系统 网络均正常的情况下组织核酸采样员和志愿者对人群进行核酸检测筛查 每名采样员的效率不同 采样效率为N人 小时 由于外界变化 采样员的效率会以M人 小时为粒度发生变化 M为采样效率浮动粒度 M N 10 输入保证N 10 的结
  • java对象clone()方法

    java赋值是复制对象引用 如果我们想要得到一个对象的副本 使用赋值操作是无法达到目的的 Test public void testassign Person p1 new Person p1 setAge 31 p1 setName Pe