2010-09-22 39 views
39

Có cách nào thanh lịch để biến một mảng nguyên thủy thành một mảng của các đối tượng chứa tương ứng hay không - ví dụ như biến một byte[] thành một ví dụ Byte[]? Hoặc tôi bị mắc kẹt với looping thông qua nó và làm nó bằng tay?Chuyển đổi mảng nguyên thủy thành mảng của các thùng chứa trong Java

Vâng, vòng lặp for không thực sự khó. Chỉ cần kinda xấu xí.

+0

Và ngược lại: http://stackoverflow.com/questions/564392/converting-an-array-of-objects-to-an-array-of-their-primitive-types –

Trả lời

63

Apache Commons

Apache Commons/Lang có một lớp ArrayUtils xác định các phương pháp này.

  • Tất cả các phương pháp gọi là toObject(...) chuyển đổi từ mảng nguyên thủy để bao bọc mảng
  • Tất cả gọi toPrimitive(...) chuyển đổi từ mảng đối tượng wrapper để mảng nguyên thủy

Ví dụ:

final int[]  original  = new int[] { 1, 2, 3 }; 
final Integer[] wrappers  = ArrayUtils.toObject(original); 
final int[]  primitivesAgain = ArrayUtils.toPrimitive(wrappers); 
assert Arrays.equals(original, primitivesAgain); 

.210

Ổi

Nhưng sau đó tôi muốn nói rằng Mảng của nguyên thủy bao bọc không phải là rất hữu ích, vì vậy bạn có thể muốn có một cái nhìn tại Guava thay vào đó, cung cấp danh sách của tất cả các loại số, được hỗ trợ bởi các mảng nguyên thủy:

List<Integer> intList = Ints.asList(1,2,3,4,5); 
List<Long> longList = Longs.asList(1L,2L,3L,4L,5L); 
// etc. 

những suy nghĩ tốt đẹp về những bộ sưu tập mảng hậu thuẫn là

  1. họ những quan điểm sống (tức là cập nhật cho mảng thay đổi danh sách và ngược lại)
  2. đối tượng trình bao bọc chỉ được tạo khi cần thiết (ví dụ:khi lặp lại danh sách)

Xem: Guava Explained/Primitives


Java 8

Mặt khác, với Java 8 lambdas/suối, bạn có thể làm cho các chuyển đổi khá đơn giản mà không sử dụng thư viện bên ngoài:

int[] primitiveInts = {1, 2, 3}; 
Integer[] wrappedInts = Arrays.stream(primitiveInts) 
           .boxed() 
           .toArray(Integer[]::new); 
int[] unwrappedInts = Arrays.stream(wrappedInts) 
          .mapToInt(Integer::intValue) 
          .toArray(); 
assertArrayEquals(primitiveInts, unwrappedInts); 

double[] primitiveDoubles = {1.1d, 2.2d, 3.3d}; 
Double[] wrappedDoubles = Arrays.stream(primitiveDoubles) 
           .boxed() 
           .toArray(Double[]::new); 
double[] unwrappedDoubles = Arrays.stream(wrappedDoubles) 
            .mapToDouble(Double::doubleValue) 
            .toArray(); 

assertArrayEquals(primitiveDoubles, unwrappedDoubles, 0.0001d); 

Lưu ý rằng Java 8 phiên bản hoạt động cho int, longdouble, nhưng không cho byte, vì Arrays.stream() chỉ bị quá tải cho int[], long[], double[] hoặc đối tượng chung T[].

+1

Có quá tải cho 'Arrays.stream (Byte [])' không? – 3yanlis1bos

+1

Giải pháp Java 8 không hoạt động đối với câu hỏi được đăng. 'Arrays.stream()' không có quá tải cho 'byte []' – Peri461

+0

@ Peri461 đúng. Tôi đã chỉ thêm các công cụ Java 8 như một suy nghĩ trong năm nay, phần còn lại của câu trả lời là vài năm cũ hơn Java 8 –

7

Bạn phải lặp qua mảng của mình.


Cập nhật sau câu trả lời @seanizer:

Về cơ bản các phương pháp toObject(byte[] array) sẽ làm vòng lặp cho bạn:

public static Byte[] toObject(byte[] array) { 
    if (array == null) { 
     return null; 
    } else if (array.length == 0) { 
     return EMPTY_BYTE_OBJECT_ARRAY; 
    } 
    final Byte[] result = new Byte[array.length]; 
    for (int i = 0; i < array.length; i++) { 
     result[i] = new Byte(array[i]); 
    } 
    return result; 
} 

Và trừ khi bạn sẽ thực sự sử dụng lib commons lang, bạn chỉ nên sử dụng lại phương pháp này và tránh sự phụ thuộc vô dụng (IMHO).

+4

Tôi không nghĩ rằng sự phụ thuộc là vô dụng. Các phương thức StringUtils. * Là một trình tiết kiệm thời gian rất lớn.ArrayUtils là một tiền thưởng :-) –

+4

@seanizer Tôi hoàn toàn đồng ý, Commons lang thực sự hữu ích, tôi chỉ nói rằng có một sự phụ thuộc vào nó cho chỉ một phương pháp tĩnh là không. –

+0

@colin sau đó tôi đồng ý quá –

7

Chỉ cần để cho thấy một sự thay thế, với Guava bạn có thể sử dụng một trong những tiện ích kiểu nguyên thủy như Bytes hoặc Ints để tạo ra một List loại wrapper:

byte[] bytes = ... 
List<Byte> byteList = Bytes.asList(bytes); 

Thay vì lặp qua và chuyển đổi từng byte , các phương thức này thực sự tạo danh sách được hỗ trợ bởi mảng đã cho. Nếu bạn thực sự cần một Byte[], điều này rõ ràng không trực tiếp cung cấp cho bạn những gì bạn cần (mặc dù bạn có thể nhận được nó bằng cách sử dụng .toArray(new Byte[bytes.length]) tất nhiên). Tuy nhiên, các bộ sưu tập rất vượt trội so với các mảng cho các đối tượng và nên được ưu tiên khi có thể.

+1

Tôi đồng ý. Quy tắc bộ sưu tập, mảng hút, quy tắc ổi (+1) –

1

Sau khi thêm a good answer, đây là một câu trả lời khủng khiếp, chỉ dành cho những cái quái của nó. Điều làm phiền tôi về lớp Apache Commons ArrayUtils là có 8 phiên bản của cùng một phương thức, chỉ cho các kiểu đầu vào khác nhau. Tôi tìm thấy một cách chung chung để chuyển đổi bất kỳ mảng nguyên thủy vào tương đương wrapper của nó (do đó làm giảm 8 phiên bản khác nhau để một). Đây là mã:

public final class ArraysUtils { 

    private ArraysUtils() { } 

    @SuppressWarnings("unchecked") 
    public static Object[] toWrapperArray(final Object primitiveArray) { 
     Objects.requireNonNull(primitiveArray, "Null values are not supported"); 
     final Class<?> cls = primitiveArray.getClass(); 
     if (!cls.isArray() || !cls.getComponentType().isPrimitive()) { 
      throw new IllegalArgumentException(
        "Only primitive arrays are supported"); 
     } 
     final int length = Array.getLength(primitiveArray); 
     if (length == 0) { 
      throw new IllegalArgumentException(
        "Only non-empty primitive arrays are supported"); 
     } 
     final Object first = Array.get(primitiveArray, 0); 
     Object[] arr = (Object[]) Array.newInstance(first.getClass(), length); 
     arr[0] = first; 
     for (int i = 1; i < length; i++) { 
      arr[i] = Array.get(primitiveArray, i); 
     } 
     return arr; 
    } 

} 

Như bạn thấy, có khá nhiều sai với phương pháp đó:

  • Không có an toàn thời gian biên dịch, tham số phương pháp có thể được bất cứ điều gì và chỉ có phương pháp riêng của mình sẽ xác nhận hợp lệ các tham số thời gian chạy, loại bỏ nghiêm ngặt các giá trị null, các mảng trống, các mảng không phải mảng và các mảng không nguyên thủy
  • Phản ánh là cần thiết
  • Không có cách nào để hỗ trợ các mảng trống mà không giữ bảng tra cứu giữa S.

Dù sao, đây là một bộ kiểm tra đối với tất cả các tình huống cần thiết, sử dụng JUnit của Parameterized Á hậu:

@RunWith(Parameterized.class) 
public class ArraysUtilsTest { 
    @Parameterized.Parameters(name = "{0}") 
    public static List<Object> parameters() { 
     return Arrays.asList(
       success(new int[]{1, 2, 3}, new Integer[]{1, 2, 3}), 
       success(new long[]{1L, 2L, 3L}, new Long[]{1L, 2L, 3L}), 
       success(new byte[]{1, 2, 3}, new Byte[]{1, 2, 3}), 
       success(new short[]{1, 2, 3}, new Short[]{1, 2, 3}), 
       success(new char[]{'a', 'b', 'c'}, new Character[]{'a', 'b', 'c'}), 
       success(new double[]{1.0, 2.0, 3.0}, new Double[]{1.0, 2.0, 3.0}), 
       success(new float[]{1.0f, 2.0f, 3.0f}, new Float[]{1.0f, 2.0f, 3.0f}), 
       success(new boolean[]{true, false, true}, new Boolean[]{true, false, true}), 
       failure(null, NullPointerException.class, "Null"), 
       failure("foo", IllegalArgumentException.class, "Non-array"), 
       failure(new String[]{"foo", "bar"}, IllegalArgumentException.class, "Non-primitive array"), 
       failure(new int[0], IllegalArgumentException.class, "Empty array") 


      ); 
    } 

    private static Object[] success(Object primitiveArray, Object[] wrapperArray) { 
     return new Object[]{ 
       primitiveArray.getClass().getCanonicalName(), 
       primitiveArray, null, wrapperArray}; 
    } 

    private static Object[] failure(Object input, 
            Class<? extends RuntimeException> exceptionClass, 
            String description) { 
     return new Object[]{description, input, exceptionClass, null}; 
    } 

    @Parameterized.Parameter(0) 
    // only used to generate the test name 
    public String scenarioName; 

    @Parameterized.Parameter(1) 
    public Object inputArray; 

    @Parameterized.Parameter(2) 
    public Class<? extends RuntimeException> expectedException; 

    @Parameterized.Parameter(3) 
    public Object[] expectedOutput; 


    @Test 
    public void runScenario() { 
     try { 
      Object[] wrapped = ArraysUtils.toWrapperArray(inputArray); 
      if (expectedException != null) { 
       fail(String.format("Expected %s to be thrown", 
            expectedException.getSimpleName())); 
      } 
      assertThat(wrapped, is(equalTo(expectedOutput))); 
     } catch (RuntimeException e) { 
      if (expectedException == null) { 
       fail(String.format("Expected no exception but got %swith message '%s'", 
            e.getClass().getSimpleName(), 
            e.getMessage())); 
      } 
      if(!expectedException.isInstance(e)){ 
       fail(String.format("Expected %s but got %s with message '%s'", 
            expectedException.getSimpleName(), 
            e.getClass().getSimpleName(), 
            e.getMessage())); 
      } 
     } 
    } 


} 
2

Dưới đây là một cách ngắn generic làm việc đó mà không sử dụng bất kỳ thư viện bên ngoài và nó hoạt động cho tất cả nguyên thủy:

import static java.lang.reflect.Array.*; 
import java.util.Arrays; 

public class DeepConverter { 

    public static void main(String args[]) {   
    long L1[][][] = {{{1,2},{3,4}}, {{5,6}}, {{7}},{{8,9,10,11}}}; 
    L1 = new long[2][0][7]; 
    Long L2[][] = (Long[][])box(L1); 
    System.out.println(Arrays.deepToString(L2));   
    } 

    public static Object box(Object src) {   
    try { 
     int length = src.getClass().isArray() ? getLength(src) : 0;   
     if(length == 0) 
      return src;   
     Object dest = newInstance(typeCastTo(wrap(get(src, 0))), length);   
     for(int i = 0; i < length; i++) 
      set(dest, i, wrap(get(src, i)));   
     return dest; 

    } catch(Exception e) { 
     throw new ClassCastException("Object to wrap must be an array of primitives with no 0 dimensions"); 
    } 
    } 

    private static Class<?> typeCastTo(Object obj) { 
    Class<?> type = obj.getClass(); 
    if(type.equals(boolean.class)) return Boolean.class; 
    if(type.equals(byte.class)) return Byte.class; 
    if(type.equals(char.class)) return Character.class; 
    if(type.equals(double.class)) return Double.class; 
    if(type.equals(float.class)) return Float.class; 
    if(type.equals(int.class)) return Integer.class; 
    if(type.equals(long.class)) return Long.class; 
    if(type.equals(short.class)) return Short.class; 
    if(type.equals(void.class)) return Void.class;   
    return type; 
    } 
} 
Các vấn đề liên quan