原型模式与深拷贝浅拷贝

原型模式

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。使用这种方式创建对象非常高效,根本无需知道对象创建的细节。

这让我想到了docker的镜像

Java中的原型模式

Java自带了原型模式clone()方法,但是使用clone()方法有两个条件

  1. 重写父类(Object类)的clone方法,将clone设置为public
  2. 实现标记性接口Cloneable

简单的例子

public class PrototyObj implements Cloneable{
    String str;
    Integer intVal;
    MyObj myObj;

    @Override
    public PrototyObj clone() throws CloneNotSupportedException {
        return (PrototyObj) super.clone();
    }
}
public class MyObj {
    String code;
    String title;
}
public class PrototypeMain {
    public static void main(String[] args) throws CloneNotSupportedException {
        PrototyObj prototyObj = new PrototyObj();
        prototyObj.intVal=88;
        prototyObj.str="88";
        MyObj myObj = new MyObj();
        myObj.code="zhangsan";
        myObj.title="张三";
        prototyObj.myObj=myObj;
        PrototyObj cloneObj = prototyObj.clone();
        System.out.println("(cloneObj==prototyObj) = " + (cloneObj == prototyObj));
        System.out.println("(cloneObj.intVal== prototyObj.intVal) = " + (cloneObj.intVal == prototyObj.intVal));
        System.out.println("(cloneObj.str==prototyObj.str) = " + (cloneObj.str == prototyObj.str));
    }
}

然后我们看下运行结果:
在这里插入图片描述
从结果中可以看到,cloneObj中所有的属性都和prototyObj是一样的。也就是我们成功的创建了一个prototyObj的克隆对象。

浅拷贝

在上面的例子中,由于PrototyObj的myObj属性不是8大基本类型,所以cloneObj中的myObj和prototyObj中的myObj是相等的,也就是指向了同一个内存地址。这种拷贝被称为浅拷贝。
由于克隆对象和原始对象都指向了同一个myObj,所以一旦原始对象的myObj发生改变,克隆对象的myObj也会对应着发生变化,就像下面这样:

public class PrototypeMain {
    public static void main(String[] args) throws CloneNotSupportedException {
        PrototyObj prototyObj = new PrototyObj();
        prototyObj.intVal=88;
        prototyObj.str="88";
        MyObj myObj = new MyObj();
        myObj.code="zhangsan";
        myObj.title="张三";
        prototyObj.myObj=myObj;
        PrototyObj cloneObj = prototyObj.clone();
        System.out.println("(cloneObj==prototyObj) = " + (cloneObj == prototyObj));
        System.out.println("(cloneObj.myObj==prototyObj.myObj) = " + (cloneObj.myObj == prototyObj.myObj));
        //浅拷贝中修改原始对象的myObj的属性将会影响拷贝对象的myObj的属性
        prototyObj.myObj.code="lisi";
        prototyObj.myObj.title="李四";
        System.out.println("cloneObj.myObj.code = " + cloneObj.myObj.code);
        System.out.println("cloneObj.myObj.title = " + cloneObj.myObj.title);
    }
}

看下运行结果,果然克隆对象的myObj的属性也受到了影响
在这里插入图片描述

深拷贝

浅拷贝中发生的问题算不上是问题,很多时候我们就是需要一个浅拷贝即可。

那么如何避免上面的问题呢?答案很简单,将myObj也复制一份,当然,我们需要对源码进行修改

  1. 首先,MyObj对象也需要实现Cloneable接口
    在这里插入图片描述
  2. PrototyObj在进行复制时,需要额外处理一下myObj属性
    在这里插入图片描述

然后, 我们再跑一次程序,就得到了如下的结果:
在这里插入图片描述
从结果中可以看到,克隆对象的myObj属性和原始对象的myObj属性已经不是指向同一个MyObj对象了。所以当原始对象的myObj属性发生改变后,克隆对象并没有收到影响。
所谓深拷贝就是复制出来的对象的每个属性以及属性的属性都和原始对象不是同一个对象

效率比较

原型模式有两个点:

  1. 方便的创建对象-------->通过clone来创建对象确实方便
  2. 高效-------->clone比我们直接new对象更高效吗?

是时候拿出我们的JMH跑一跑了

JMH测试样例

@BenchmarkMode({Mode.SampleTime})
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(time = 2, batchSize = 100)
@Measurement(time = 2, batchSize = 500)
@Fork(2)
@Threads(10)
@State(value = Scope.Benchmark)
public class PrototypeTest {

    private PrototyObj prototyObj;

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(PrototypeTest.class.getSimpleName())
                .result("PrototypeTest_result.json")
                .resultFormat(ResultFormatType.JSON).build();
        new Runner(opt).run();
    }

    @Setup
    public void init() {
        prototyObj = new PrototyObj();
        prototyObj.intVal=88;
        prototyObj.str="88";
        MyObj myObj = new MyObj();
        myObj.code="zhangsan";
        myObj.title="张三";
        prototyObj.myObj = myObj;
    }

    @Benchmark
    public PrototyObj testClone() throws CloneNotSupportedException {
        return prototyObj.clone();
    }

    @Benchmark
    public PrototyObj testNew() {
        PrototyObj clone = new PrototyObj();
        clone.intVal = prototyObj.intVal;
        clone.str=prototyObj.str;
        MyObj oriMyObj = prototyObj.myObj;
        MyObj myObj = new MyObj();
        myObj.code = oriMyObj.code;
        myObj.title = oriMyObj.title;
        clone.myObj =myObj;
        return clone;
    }
}

测试结果

# JMH version: 1.33
# VM version: JDK 1.8.0_261, Java HotSpot(TM) 64-Bit Server VM, 25.261-b12
# VM invoker: C:\Program Files\Java\jdk1.8.0_261\jre\bin\java.exe
# VM options: -javaagent:D:\jetbrains\IntelliJ IDEA 2021.2\lib\idea_rt.jar=56720:D:\jetbrains\IntelliJ IDEA 2021.2\bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 5 iterations, 2 s each, 100 calls per op
# Measurement: 5 iterations, 2 s each, 500 calls per op
# Timeout: 10 min per iteration
# Threads: 10 threads, will synchronize iterations
# Benchmark mode: Sampling time
# Benchmark: com.example.jmh.PrototypeTest.testClone

# Run progress: 0.00% complete, ETA 00:01:20
# Fork: 1 of 2
# Warmup Iteration   1: 5518.031 ±(99.9%) 264.531 ns/op
# Warmup Iteration   2: 5658.041 ±(99.9%) 1082.759 ns/op
# Warmup Iteration   3: 6559.181 ±(99.9%) 627.511 ns/op
# Warmup Iteration   4: 4881.049 ±(99.9%) 368.714 ns/op
# Warmup Iteration   5: 7646.121 ±(99.9%) 1032.180 ns/op
Iteration   1: 22776.367 ±(99.9%) 916.867 ns/op
                 testClone·p0.00:   6800.000 ns/op
                 testClone·p0.50:   15488.000 ns/op
                 testClone·p0.90:   19072.000 ns/op
                 testClone·p0.95:   25184.000 ns/op
                 testClone·p0.99:   123648.000 ns/op
                 testClone·p0.999:  988408.832 ns/op
                 testClone·p0.9999: 7048259.174 ns/op
                 testClone·p1.00:   43319296.000 ns/op

Iteration   2: 24346.085 ±(99.9%) 1974.777 ns/op
                 testClone·p0.00:   6696.000 ns/op
                 testClone·p0.50:   15392.000 ns/op
                 testClone·p0.90:   19072.000 ns/op
                 testClone·p0.95:   25472.000 ns/op
                 testClone·p0.99:   121856.000 ns/op
                 testClone·p0.999:  1094416.384 ns/op
                 testClone·p0.9999: 11166567.629 ns/op
                 testClone·p1.00:   157548544.000 ns/op

Iteration   3: 22157.449 ±(99.9%) 675.149 ns/op
                 testClone·p0.00:   6800.000 ns/op
                 testClone·p0.50:   15600.000 ns/op
                 testClone·p0.90:   18592.000 ns/op
                 testClone·p0.95:   24480.000 ns/op
                 testClone·p0.99:   115467.520 ns/op
                 testClone·p0.999:  1071736.832 ns/op
                 testClone·p0.9999: 7350516.122 ns/op
                 testClone·p1.00:   21364736.000 ns/op

Iteration   4: 20359.747 ±(99.9%) 498.717 ns/op
                 testClone·p0.00:   6600.000 ns/op
                 testClone·p0.50:   15600.000 ns/op
                 testClone·p0.90:   19200.000 ns/op
                 testClone·p0.95:   24672.000 ns/op
                 testClone·p0.99:   105984.000 ns/op
                 testClone·p0.999:  577536.000 ns/op
                 testClone·p0.9999: 3781365.760 ns/op
                 testClone·p1.00:   25559040.000 ns/op

Iteration   5: 23996.060 ±(99.9%) 1572.413 ns/op
                 testClone·p0.00:   6696.000 ns/op
                 testClone·p0.50:   15488.000 ns/op
                 testClone·p0.90:   18688.000 ns/op
                 testClone·p0.95:   24672.000 ns/op
                 testClone·p0.99:   120720.640 ns/op
                 testClone·p0.999:  1130932.224 ns/op
                 testClone·p0.9999: 10015722.701 ns/op
                 testClone·p1.00:   110231552.000 ns/op


# Run progress: 25.00% complete, ETA 00:01:06
# Fork: 2 of 2
# Warmup Iteration   1: 5691.404 ±(99.9%) 364.499 ns/op
# Warmup Iteration   2: 3977.670 ±(99.9%) 174.700 ns/op
# Warmup Iteration   3: 4107.415 ±(99.9%) 105.080 ns/op
# Warmup Iteration   4: 6307.642 ±(99.9%) 387.018 ns/op
# Warmup Iteration   5: 5057.968 ±(99.9%) 196.002 ns/op
Iteration   1: 18594.193 ±(99.9%) 193.192 ns/op
                 testClone·p0.00:   6400.000 ns/op
                 testClone·p0.50:   15792.000 ns/op
                 testClone·p0.90:   18080.000 ns/op
                 testClone·p0.95:   23200.000 ns/op
                 testClone·p0.99:   88832.000 ns/op
                 testClone·p0.999:  430985.728 ns/op
                 testClone·p0.9999: 1875542.221 ns/op
                 testClone·p1.00:   6479872.000 ns/op

Iteration   2: 17515.850 ±(99.9%) 249.191 ns/op
                 testClone·p0.00:   6200.000 ns/op
                 testClone·p0.50:   15888.000 ns/op
                 testClone·p0.90:   17696.000 ns/op
                 testClone·p0.95:   20576.000 ns/op
                 testClone·p0.99:   49344.000 ns/op
                 testClone·p0.999:  334231.040 ns/op
                 testClone·p0.9999: 2072817.664 ns/op
                 testClone·p1.00:   18186240.000 ns/op

Iteration   3: 17655.096 ±(99.9%) 216.672 ns/op
                 testClone·p0.00:   6400.000 ns/op
                 testClone·p0.50:   16000.000 ns/op
                 testClone·p0.90:   17696.000 ns/op
                 testClone·p0.95:   20288.000 ns/op
                 testClone·p0.99:   59722.240 ns/op
                 testClone·p0.999:  377344.000 ns/op
                 testClone·p0.9999: 1784104.960 ns/op
                 testClone·p1.00:   7839744.000 ns/op

Iteration   4: 17349.219 ±(99.9%) 190.369 ns/op
                 testClone·p0.00:   6400.000 ns/op
                 testClone·p0.50:   16000.000 ns/op
                 testClone·p0.90:   17696.000 ns/op
                 testClone·p0.95:   19872.000 ns/op
                 testClone·p0.99:   50240.000 ns/op
                 testClone·p0.999:  330240.000 ns/op
                 testClone·p0.9999: 1307788.493 ns/op
                 testClone·p1.00:   10059776.000 ns/op

Iteration   5: 17475.811 ±(99.9%) 173.673 ns/op
                 testClone·p0.00:   6400.000 ns/op
                 testClone·p0.50:   15888.000 ns/op
                 testClone·p0.90:   17696.000 ns/op
                 testClone·p0.95:   20480.000 ns/op
                 testClone·p0.99:   56256.000 ns/op
                 testClone·p0.999:  325248.000 ns/op
                 testClone·p0.9999: 1695232.000 ns/op
                 testClone·p1.00:   5046272.000 ns/op



Result "com.example.jmh.PrototypeTest.testClone":
  N = 4893390
  mean =  20186.672 ±(99.9%) 272.095 ns/op

  Histogram, ns/op:
    [        0.000,  12500000.000) = 4893281 
    [ 12500000.000,  25000000.000) = 74 
    [ 25000000.000,  37500000.000) = 20 
    [ 37500000.000,  50000000.000) = 6 
    [ 50000000.000,  62500000.000) = 2 
    [ 62500000.000,  75000000.000) = 1 
    [ 75000000.000,  87500000.000) = 2 
    [ 87500000.000, 100000000.000) = 1 
    [100000000.000, 112500000.000) = 2 
    [112500000.000, 125000000.000) = 0 
    [125000000.000, 137500000.000) = 0 
    [137500000.000, 150000000.000) = 0 
    [150000000.000, 162500000.000) = 1 
    [162500000.000, 175000000.000) = 0 
    [175000000.000, 187500000.000) = 0 

  Percentiles, ns/op:
      p(0.0000) =   6200.000 ns/op
     p(50.0000) =  15696.000 ns/op
     p(90.0000) =  18176.000 ns/op
     p(95.0000) =  23200.000 ns/op
     p(99.0000) =  90496.000 ns/op
     p(99.9000) = 635904.000 ns/op
     p(99.9900) = 4303436.186 ns/op
     p(99.9990) = 20862104.371 ns/op
     p(99.9999) = 84163589.832 ns/op
    p(100.0000) = 157548544.000 ns/op


# JMH version: 1.33
# VM version: JDK 1.8.0_261, Java HotSpot(TM) 64-Bit Server VM, 25.261-b12
# VM invoker: C:\Program Files\Java\jdk1.8.0_261\jre\bin\java.exe
# VM options: -javaagent:D:\jetbrains\IntelliJ IDEA 2021.2\lib\idea_rt.jar=56720:D:\jetbrains\IntelliJ IDEA 2021.2\bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 5 iterations, 2 s each, 100 calls per op
# Measurement: 5 iterations, 2 s each, 500 calls per op
# Timeout: 10 min per iteration
# Threads: 10 threads, will synchronize iterations
# Benchmark mode: Sampling time
# Benchmark: com.example.jmh.PrototypeTest.testNew

# Run progress: 50.00% complete, ETA 00:00:43
# Fork: 1 of 2
# Warmup Iteration   1: 5233.929 ±(99.9%) 406.860 ns/op
# Warmup Iteration   2: 4409.203 ±(99.9%) 355.687 ns/op
# Warmup Iteration   3: 4140.384 ±(99.9%) 191.148 ns/op
# Warmup Iteration   4: 4425.205 ±(99.9%) 274.721 ns/op
# Warmup Iteration   5: 4703.808 ±(99.9%) 315.689 ns/op
Iteration   1: 20516.239 ±(99.9%) 1245.102 ns/op
                 testNew·p0.00:   4000.000 ns/op
                 testNew·p0.50:   12800.000 ns/op
                 testNew·p0.90:   17184.000 ns/op
                 testNew·p0.95:   21888.000 ns/op
                 testNew·p0.99:   125696.000 ns/op
                 testNew·p0.999:  1052672.000 ns/op
                 testNew·p0.9999: 7712489.472 ns/op
                 testNew·p1.00:   115474432.000 ns/op

Iteration   2: 18789.290 ±(99.9%) 721.128 ns/op
                 testNew·p0.00:   3800.000 ns/op
                 testNew·p0.50:   13600.000 ns/op
                 testNew·p0.90:   16896.000 ns/op
                 testNew·p0.95:   22272.000 ns/op
                 testNew·p0.99:   88832.000 ns/op
                 testNew·p0.999:  773120.000 ns/op
                 testNew·p0.9999: 5905665.229 ns/op
                 testNew·p1.00:   43646976.000 ns/op

Iteration   3: 18495.429 ±(99.9%) 579.992 ns/op
                 testNew·p0.00:   3900.000 ns/op
                 testNew·p0.50:   13296.000 ns/op
                 testNew·p0.90:   16384.000 ns/op
                 testNew·p0.95:   19584.000 ns/op
                 testNew·p0.99:   93440.000 ns/op
                 testNew·p0.999:  899610.624 ns/op
                 testNew·p0.9999: 4818875.187 ns/op
                 testNew·p1.00:   29523968.000 ns/op

Iteration   4: 18666.115 ±(99.9%) 588.180 ns/op
                 testNew·p0.00:   3800.000 ns/op
                 testNew·p0.50:   13888.000 ns/op
                 testNew·p0.90:   16896.000 ns/op
                 testNew·p0.95:   21088.000 ns/op
                 testNew·p0.99:   87808.000 ns/op
                 testNew·p0.999:  751616.000 ns/op
                 testNew·p0.9999: 5836304.384 ns/op
                 testNew·p1.00:   27951104.000 ns/op

Iteration   5: 20645.492 ±(99.9%) 1139.081 ns/op
                 testNew·p0.00:   3900.000 ns/op
                 testNew·p0.50:   12800.000 ns/op
                 testNew·p0.90:   16288.000 ns/op
                 testNew·p0.95:   21984.000 ns/op
                 testNew·p0.99:   126325.760 ns/op
                 testNew·p0.999:  1158332.416 ns/op
                 testNew·p0.9999: 8136110.899 ns/op
                 testNew·p1.00:   50987008.000 ns/op


# Run progress: 75.00% complete, ETA 00:00:21
# Fork: 2 of 2
# Warmup Iteration   1: 5381.014 ±(99.9%) 345.255 ns/op
# Warmup Iteration   2: 5295.847 ±(99.9%) 567.626 ns/op
# Warmup Iteration   3: 5559.507 ±(99.9%) 442.106 ns/op
# Warmup Iteration   4: 4024.242 ±(99.9%) 489.348 ns/op
# Warmup Iteration   5: 4709.293 ±(99.9%) 412.818 ns/op
Iteration   1: 18146.819 ±(99.9%) 671.877 ns/op
                 testNew·p0.00:   3700.000 ns/op
                 testNew·p0.50:   14192.000 ns/op
                 testNew·p0.90:   16480.000 ns/op
                 testNew·p0.95:   18592.000 ns/op
                 testNew·p0.99:   89088.000 ns/op
                 testNew·p0.999:  680060.928 ns/op
                 testNew·p0.9999: 3419793.818 ns/op
                 testNew·p1.00:   58195968.000 ns/op

Iteration   2: 18237.222 ±(99.9%) 349.829 ns/op
                 testNew·p0.00:   3900.000 ns/op
                 testNew·p0.50:   14096.000 ns/op
                 testNew·p0.90:   16992.000 ns/op
                 testNew·p0.95:   20480.000 ns/op
                 testNew·p0.99:   100096.000 ns/op
                 testNew·p0.999:  741957.632 ns/op
                 testNew·p0.9999: 3071115.264 ns/op
                 testNew·p1.00:   13877248.000 ns/op

Iteration   3: 18822.709 ±(99.9%) 451.900 ns/op
                 testNew·p0.00:   3800.000 ns/op
                 testNew·p0.50:   14192.000 ns/op
                 testNew·p0.90:   17088.000 ns/op
                 testNew·p0.95:   23488.000 ns/op
                 testNew·p0.99:   107520.000 ns/op
                 testNew·p0.999:  762880.000 ns/op
                 testNew·p0.9999: 3489378.304 ns/op
                 testNew·p1.00:   23003136.000 ns/op

Iteration   4: 20049.312 ±(99.9%) 1085.889 ns/op
                 testNew·p0.00:   4000.000 ns/op
                 testNew·p0.50:   13296.000 ns/op
                 testNew·p0.90:   16288.000 ns/op
                 testNew·p0.95:   19296.000 ns/op
                 testNew·p0.99:   95744.000 ns/op
                 testNew·p0.999:  909457.408 ns/op
                 testNew·p0.9999: 10102367.846 ns/op
                 testNew·p1.00:   45875200.000 ns/op

Iteration   5: 18218.396 ±(99.9%) 375.050 ns/op
                 testNew·p0.00:   3900.000 ns/op
                 testNew·p0.50:   14800.000 ns/op
                 testNew·p0.90:   16896.000 ns/op
                 testNew·p0.95:   18976.000 ns/op
                 testNew·p0.99:   82798.080 ns/op
                 testNew·p0.999:  762208.256 ns/op
                 testNew·p0.9999: 2597145.805 ns/op
                 testNew·p1.00:   12812288.000 ns/op



Result "com.example.jmh.PrototypeTest.testNew":
  N = 5052013
  mean =  19049.281 ±(99.9%) 246.082 ns/op

  Histogram, ns/op:
    [        0.000,  12500000.000) = 5051859 
    [ 12500000.000,  25000000.000) = 115 
    [ 25000000.000,  37500000.000) = 27 
    [ 37500000.000,  50000000.000) = 7 
    [ 50000000.000,  62500000.000) = 4 
    [ 62500000.000,  75000000.000) = 0 
    [ 75000000.000,  87500000.000) = 0 
    [ 87500000.000, 100000000.000) = 0 
    [100000000.000, 112500000.000) = 0 
    [112500000.000, 125000000.000) = 1 
    [125000000.000, 137500000.000) = 0 
    [137500000.000, 150000000.000) = 0 
    [150000000.000, 162500000.000) = 0 
    [162500000.000, 175000000.000) = 0 
    [175000000.000, 187500000.000) = 0 

  Percentiles, ns/op:
      p(0.0000) =   3700.000 ns/op
     p(50.0000) =  13696.000 ns/op
     p(90.0000) =  16800.000 ns/op
     p(95.0000) =  20800.000 ns/op
     p(99.0000) =  99712.000 ns/op
     p(99.9000) = 850944.000 ns/op
     p(99.9900) = 5251014.656 ns/op
     p(99.9990) = 22952004.157 ns/op
     p(99.9999) = 50443805.260 ns/op
    p(100.0000) = 115474432.000 ns/op


# Run complete. Total time: 00:01:26

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.

Benchmark                                    Mode      Cnt          Score     Error  Units
PrototypeTest.testClone                    sample  4893390      20186.672 ± 272.095  ns/op
PrototypeTest.testClone:testClone·p0.00    sample                6200.000            ns/op
PrototypeTest.testClone:testClone·p0.50    sample               15696.000            ns/op
PrototypeTest.testClone:testClone·p0.90    sample               18176.000            ns/op
PrototypeTest.testClone:testClone·p0.95    sample               23200.000            ns/op
PrototypeTest.testClone:testClone·p0.99    sample               90496.000            ns/op
PrototypeTest.testClone:testClone·p0.999   sample              635904.000            ns/op
PrototypeTest.testClone:testClone·p0.9999  sample             4303436.186            ns/op
PrototypeTest.testClone:testClone·p1.00    sample           157548544.000            ns/op
PrototypeTest.testNew                      sample  5052013      19049.281 ± 246.082  ns/op
PrototypeTest.testNew:testNew·p0.00        sample                3700.000            ns/op
PrototypeTest.testNew:testNew·p0.50        sample               13696.000            ns/op
PrototypeTest.testNew:testNew·p0.90        sample               16800.000            ns/op
PrototypeTest.testNew:testNew·p0.95        sample               20800.000            ns/op
PrototypeTest.testNew:testNew·p0.99        sample               99712.000            ns/op
PrototypeTest.testNew:testNew·p0.999       sample              850944.000            ns/op
PrototypeTest.testNew:testNew·p0.9999      sample             5251014.656            ns/op
PrototypeTest.testNew:testNew·p1.00        sample           115474432.000            ns/op

从结果上看,在我的测试对象上看new的效率与clone的效率基本持平。不过这样也很不错了,对于属性非常多的对象,可以安心的使用clone方法而不用担心效率问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值