Có tương đương với memcpy () trong Java không?


81

Tôi có một byte [] và muốn sao chép nó vào một byte khác []. Có thể tôi đang hiển thị nền 'C' đơn giản của mình ở đây, nhưng có tương đương với memcpy () trên mảng byte trong Java không?

Câu trả lời:


84

Bạn có thể thử System.arraycopyhoặc sử dụng các hàm mảng trong Arrayslớp như java.util.Arrays.copyOf. Cả hai đều sẽ mang lại cho bạn hiệu suất nguyên bản.

Arrays.copyOf có lẽ thuận lợi cho việc dễ đọc, nhưng chỉ được giới thiệu trong java 1.6.

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

Tôi nghĩ rằng lựa chọn thứ hai là "hợp lý" hơn. Tôi chưa bao giờ hiểu tại sao System.arraycopy () lại ở đâu, một trong những vị trí vụng về nhất có thể.
sinuhepop 25/07/10

@Sinuhe - nó ở đó vì lý do lịch sử.
Stephen C,

29
Đây KHÔNG phải là câu trả lời chính xác. memcpy () không cấp phát dữ liệu, chỉ sao chép vào bộ đệm hiện có. Trong khi Arrays.copyOf () cấp phát bộ nhớ mới rõ ràng.
splinux

102

Sử dụng System.arraycopy ()

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

Thí dụ,

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


hoặc sử dụng Ví dụ Arrays.copyOf ()
,

target = Arrays.copyOf(source, length);

java.util.Arrays.copyOf(byte[] source, int length)đã được thêm vào JDK 1.6.

Các copyOf()phương pháp sử dụng System.arrayCopy()để tạo một bản sao của mảng, nhưng linh hoạt hơn clone()vì bạn có thể tạo các bản sao của các bộ phận của một mảng.


5
Arrays.copyOf () cũng cấp phát bộ nhớ. trong ví dụ của bạn nếu bạn thay đổi String [] target = new String [4]; và sau đó target = Arrays.copyOf () nó tạo ra một đích mới là String [3]. Không phải là hành vi ghi nhớ.
MikeF

Arrays.copyOf sử dụng nội bộ System.arraycopy, một phương thức gốc.
Gajraj Tanwar

8

Nếu bạn chỉ muốn có một bản sao chính xác của mảng một chiều, hãy sử dụng clone().

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

Đối với các hoạt động sao chép mảng khác, hãy sử dụng System.arrayCopy/ Arrays.copyOfnhư Tom gợi ý .

Nói chung, clonenên tránh, nhưng đây là một ngoại lệ đối với quy tắc.


Xem thêm chi tiết trong câu trả lời được chấp nhận cho stackoverflow.com/questions/3208899/… .
Andy Thomas

5

Bạn có thể sử dụng System.arrayCopy . Nó sao chép các phần tử từ một mảng nguồn sang một mảng đích. Việc triển khai Sun sử dụng trình lắp ráp được tối ưu hóa bằng tay, vì vậy quá trình này diễn ra nhanh chóng.


3

Java thực sự có một cái gì đó giống như memcpy (). Lớp Không an toàn có phương thức copyMemory () về cơ bản giống với memcpy (). Tất nhiên, giống như memcpy (), nó không cung cấp sự bảo vệ khỏi lớp phủ bộ nhớ, phá hủy dữ liệu, v.v. Không rõ nó thực sự là memcpy () hay memmove (). Nó có thể được sử dụng để sao chép từ địa chỉ thực sang địa chỉ thực hoặc từ tài liệu tham khảo sang tài liệu tham khảo. Lưu ý rằng nếu các tham chiếu được sử dụng, bạn phải cung cấp một khoảng bù (nếu không JVM sẽ chết càng sớm càng tốt).

Unsafe.copyMemory () hoạt động (tối đa 2 GB mỗi giây trên máy tính cũ mệt mỏi của tôi). Sử dụng có nguy cơ của riêng bạn. Lưu ý rằng lớp Không an toàn không tồn tại cho tất cả các triển khai JVM.


xin lỗi vì đã xem tất cả ngữ nghĩa thú cưng trên chủ đề cổ xưa này, nhưng bạn có thể cho tôi một ví dụ về cách làm điều đó với một loạt các tham chiếu. Và nó có nhanh hơn đối với lượng dữ liệu nhỏ (như 1-4 MB) hay chỉ xứng đáng trong trường hợp dữ liệu lớn hơn như 2GB bạn đã đề cập?
FinnTheHuman

2
Sử dụng sun.misc.Unsafelớp được coi là một hành vi xấu "hack" b / c đó là một lớp gói riêng . Ngoài ra, bắt đầu từ Java 9, nó sẽ không còn khả dụng nữa, vì vậy việc cố gắng sử dụng lớp này cũng giống như việc bạn cầu xin mã của bạn bị hỏng bất ngờ.
code_dredd


0

Sử dụng byteBufferViewVarHandle hoặc byteArrayViewVarHandle.

Điều này sẽ cho phép bạn sao chép trực tiếp một mảng "longs" vào một mảng "gấp đôi" và tương tự như sau:

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());

Điều này sẽ cho phép bạn thực hiện các thao tác hack như:

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);

0

Không. Java không có tương đương với memcpy. Java có một tương đương với memmovethay vào đó.

Nếu các đối số src và dest tham chiếu đến cùng một đối tượng mảng, thì việc sao chép được thực hiện như thể các thành phần tại các vị trí từ srcPos đến srcPos + length-1 lần đầu tiên được sao chép vào một mảng tạm thời với các thành phần độ dài và sau đó nội dung của mảng tạm thời là được sao chép vào các vị trí destPos thông qua destPos + length-1 của mảng đích.

Tài liệu Oracle

Nó rất có thể System.arraycopysẽ không bao giờ có cùng hiệu suất như memcpythể srcdesttham chiếu đến cùng một mảng. Thông thường điều này sẽ đủ nhanh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.