【问题标题】:Is there an equivalent to memcpy() in Java?Java中是否有等效于memcpy()的方法?
【发布时间】:2011-03-20 17:45:39
【问题描述】:

我有一个字节[],想将它复制到另一个字节[]。也许我在这里展示了我简单的“C”背景,但是在 Java 中的字节数组上是否有与 memcpy() 等效的方法?

【问题讨论】:

    标签: java bytearray


    【解决方案1】:

    使用System.arraycopy()

    System.arraycopy(sourceArray, 
                     sourceStartIndex,
                     targetArray,
                     targetStartIndex,
                     length);
    

    例子,

    String[] source = { "alpha", "beta", "gamma" };
    String[] target = new String[source.length];
    System.arraycopy(source, 0, target, 0, source.length);
    


    或使用Arrays.copyOf()
    例如,

    target = Arrays.copyOf(source, length);
    

    java.util.Arrays.copyOf(byte[] source, int length) 是在 JDK 1.6 中添加的。

    copyOf() 方法使用 System.arrayCopy() 来制作数组的副本,但比 clone() 更灵活,因为您可以制作零件的副本一个数组。

    【讨论】:

    • Arrays.copyOf() 也分配内存。在您的示例中,如果您更改 String[] target = new String[4];然后 target = Arrays.copyOf() 它创建一个新的目标,它是一个字符串 [3]。不是内存复制行为。
    • Arrays.copyOf 内部使用 System.arraycopy 这是一个本地方法。
    【解决方案2】:

    您可以尝试System.arraycopy 或使用Arrays 类中的数组函数,例如java.util.Arrays.copyOf。两者都应该在后台为您提供本机性能。

    Arrays.copyOf 可能有利于可读性,但仅在 java 1.6 中引入。

     byte[] src = {1, 2, 3, 4};
     byte[] dst = Arrays.copyOf(src, src.length);
     System.out.println(Arrays.toString(dst));
    

    【讨论】:

    • 我认为第二个选项更“合乎逻辑”。我从来不明白为什么 System.arraycopy() 在哪里,可能是最笨拙的位置之一。
    • @Sinuhe - 出于历史原因。
    • 这不是正确的答案。 memcpy() 不分配数据,仅复制到现有缓冲区。而 Arrays.copyOf() 明确分配新内存。
    【解决方案3】:

    如果您只想要一维数组的精确副本,请使用clone()

    byte[] array = { 0x0A, 0x01 };
    byte[] copy = array.clone();
    

    对于其他数组复制操作,使用System.arrayCopy/Arrays.copyOf作为Tom suggests

    一般来说,应该避免clone,但这是规则的一个例外。

    【讨论】:

    【解决方案4】:

    您可以使用System.arrayCopy。它将元素从源数组复制到目标数组。 Sun 实现使用手动优化的汇编程序,因此速度很快。

    【讨论】:

      【解决方案5】:

      Java 实际上确实有类似 memcpy() 的东西。 Unsafe 类有一个与 memcpy() 基本相同的 copyMemory() 方法。当然,和 memcpy() 一样,它不提供内存覆盖、数据破坏等保护。不清楚它是真的 memcpy() 还是 memmove()。它可用于从实际地址复制到实际地址或从引用复制到引用。请注意,如果使用引用,则必须提供偏移量(否则 JVM 将尽快死亡)。

      Unsafe.copyMemory() 可以正常工作(在我老旧的 PC 上每秒最多 2 GB)。使用风险自负。请注意,并非所有 JVM 实现都存在 Unsafe 类。

      【讨论】:

      • 很抱歉在这个古老的线程上使用了所有的宠物语义,但你能给我一个例子,说明如何使用一系列参考资料来做到这一点。对于少量数据(如 1-4 MB)是否更快,还是仅在您提到的 2GB 等较大数据的情况下值得?
      • 使用sun.misc.Unsafe 类被认为是一种不好的做法“hack”b/c 它是一个 private 包类。另外,从 Java 9 开始,它就不再可用了,所以尝试使用这个类就等于乞求你的代码意外中断。
      【解决方案6】:

      您可以使用System.arraycopy

      【讨论】:

        【解决方案7】:

        当你使用 JDK 1.5+ 时你应该使用

        System.arraycopy()
        

        代替

        Arrays.copyOfRange()
        

        因为 Arrays.copyOfRange() 直到 JDK 1.6 才添加。所以你可能会得到

        Java - “Cannot Find Symbol” error
        

        在该版本的 JDK 中调用 Arrays.copyOfRange 时。

        【讨论】:

          【解决方案8】:

          使用byteBufferViewVarHandle 或 byteArrayViewVarHandle。

          这将让您将“longs”数组直接复制到“doubles”数组中,类似于:

          public long[] toLongs(byte[] buf) {
              int end = buf.length >> 3;
              long[] newArray = new long[end];
              for (int ii = 0; ii < end; ++ii) {
                  newArray[ii] = (long)AS_LONGS_VH.get(buf, ALIGN_OFFSET + ii << 3);
              }
          }
          
          private static final ALIGN_OFFSET = ByteBuffer.wrap(new byte[0]).alignmentOffset(8); 
          private static final VarHandle AS_LONGS_VH = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.nativeOrder());
          

          这会让你做一些黑客攻击:

          float thefloat = 0.4;
          int floatBits;
          _Static_assert(sizeof theFloat == sizeof floatBits, "this bit twiddling hack requires floats to be equal in size to ints");
          memcpy(&floatBits, &thefloat, sizeof floatBits);
          

          【讨论】:

            【解决方案9】:

            没有。Java 没有 memcpy 的等价物。 Java 有一个等价于 memmove 的代替。

            如果 src 和 dest 参数引用同一个数组对象,则执行复制,就好像首先将位置 srcPos 到 srcPos+length-1 的组件复制到具有长度组件的临时数组,然后复制临时数组通过目标数组的 destPos+length-1 复制到位置 destPos 中。

            Oracle Docs

            如果srcdest 引用同一个数组,System.arraycopy 很可能永远不会具有与memcpy 相同的性能。不过通常这会足够快。

            【讨论】:

              猜你喜欢
              • 2012-11-21
              • 1970-01-01
              • 2014-04-06
              • 2019-09-12
              • 1970-01-01
              • 1970-01-01
              • 2018-07-19
              • 2010-09-16
              • 1970-01-01
              相关资源
              最近更新 更多