programing

힙에 새 어레이를 생성하지 않고 Java에서 어레이 세그먼트 가져오기

prostudy 2022. 7. 4. 22:13
반응형

힙에 새 어레이를 생성하지 않고 Java에서 어레이 세그먼트 가져오기

Java에서 어레이 세그먼트를 반환하는 메서드를 찾고 있습니다.예를 들어 바이트 배열의 4번째 및 5번째 바이트를 포함하는 바이트 배열을 가져오는 것입니다.그러기 위해서만 히프 메모리에 새로운 바이트 배열을 작성할 필요는 없습니다.현재 다음과 같은 코드를 가지고 있습니다.

doSomethingWithTwoBytes(byte[] twoByteArray);

void someMethod(byte[] bigArray)
{
      byte[] x = {bigArray[4], bigArray[5]};
      doSomethingWithTwoBytes(x);
}

할 수 있는 요.doSomething(bigArray.getSubArray(4, 2))2번, 4번, 두 번째, 2번

면책사항:이 답변은 질문의 제약에 부합하지 않습니다.

그러기 위해서만 히프 메모리에 새로운 바이트 배열을 작성할 필요는 없습니다.

(솔직히 대답은 삭제할 가치가 있다고 생각합니다. @unique72의 답은 맞습니다. 이 편집은 잠시 보류하고 나서, 이 회답은 삭제합니다.)


히프를 추가 할당하지 않고 어레이에 직접 할당하는 방법은 알 수 없지만 하위 목록 래퍼를 사용하는 다른 답변은 래퍼에만 추가 할당되며 어레이에는 할당되지 않으므로 대규모 어레이의 경우 유용합니다.

즉, 간결함을 요구하는 경우 유틸리티 방식은 Java 6(2006년 후반?)에서 도입되었습니다.

byte [] a = new byte [] {0, 1, 2, 3, 4, 5, 6, 7};

// get a[4], a[5]

byte [] subArray = Arrays.copyOfRange(a, 4, 6);

Arrays.asList(myArray) 「신규」에의 대표자ArrayList(myArray)어레이를 복사하지 않고 참조만 저장합니다.「」를 사용합니다.List.subList(start, end) 후, 그 a가 .SubList원래 목록만 참조합니다(여전히 어레이만 참조).알았다.

포인터 스타일의 에일리어싱 방식을 찾고 있다면 공간을 할당하고 데이터를 복사할 필요도 없습니다.

System.arraycopy()는, 송신원으로부터 송신지에 카피됩니다.또, 이 유틸리티에 대해서 효율이 요구됩니다.대상 어레이를 할당해야 합니다.

가지 을 1로 입니다.java.nio.ByteBuffer put함수를 absolute put/get으로

예:

doSomething(ByteBuffer twoBytes) {
    byte b1 = twoBytes.get(0);
    byte b2 = twoBytes.get(1);
    ...
}

void someMethod(byte[] bigArray) {
      int offset = 4;
      int length = 2;
      doSomething(ByteBuffer.wrap(bigArray, offset, length).slice());
}

, 둘 다 요.wrap() ★★★★★★★★★★★★★★★★★」slice()부터, syslogwrap()그 자체는 상대적인 풋/게트 함수에만 영향을 미치며 절대 함수는 영향을 미치지 않습니다.

ByteBuffer이해하기 어렵지만 효율적으로 구현될 가능성이 높고 배울 가치가 있습니다.

java.nio를 사용합니다.버퍼의다양한 원시 타입의 버퍼를 위한 경량 래퍼로 슬라이스, 위치, 변환, 바이트 순서 등을 관리할 수 있습니다.

바이트가 스트림에서 생성된 경우 NIO 버퍼는 네이티브리소스로 지원되는 버퍼를 생성하는 "다이렉트 모드"를 사용할 수 있습니다.이를 통해 많은 경우 성능이 향상될 수 있습니다.

Apache Commons에서 ArrayUtils.subarray를 사용할 수 있습니다.완벽하지는 않지만, 보다 직관적으로System.arraycopy.단점은 이것이 당신의 코드에 또 다른 의존성을 가져온다는 것입니다.

subList의 답변은 이미 여기에 있습니다만, 카피가 아닌 실제의 서브 리스트임을 나타내는 코드는 다음과 같습니다.

public class SubListTest extends TestCase {
    public void testSubarray() throws Exception {
        Integer[] array = {1, 2, 3, 4, 5};
        List<Integer> list = Arrays.asList(array);
        List<Integer> subList = list.subList(2, 4);
        assertEquals(2, subList.size());
        assertEquals((Integer) 3, subList.get(0));
        list.set(2, 7);
        assertEquals((Integer) 7, subList.get(0));
    }
}

그러나 어레이에서 직접 이 작업을 수행하는 좋은 방법은 없다고 생각합니다.

List.subList(int startIndex, int endIndex)

List 을 할 수 .subList해야 합니다원시 배열에서는 일종의 오프셋 제한을 추적해야 합니다. ByteBuffer에는 제가 들은 것과 유사한 옵션이 있습니다.

편집: 편리한 메서드를 담당하고 있는 경우, (Java 자체의 많은 어레이 관련 메서드에서와 같이) 경계로 정의할 수 있습니다.

doUseful(byte[] arr, int start, int len) {
    // implementation here
}
doUseful(byte[] arr) {
    doUseful(arr, 0, arr.length);
}

그러나 어레이 요소 자체에 대해 작업하는 경우(예: 무언가를 계산하고 결과를 다시 쓰는 경우)는 명확하지 않습니다.

하나의 옵션은 어레이 전체와 시작 및 종료 인덱스를 전달하고 전달된 어레이 전체에 걸쳐 반복하지 않고 이들 인덱스를 반복하는 것입니다.

void method1(byte[] array) {
    method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
    for ( int i = start; i <= end; i++ ) {
        ....
    }
}

Java ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」하는 경우도 ).ClassCastException어레이의 경우 오브젝트의 시작 부분에도 길이가 포함됩니다.그 후 데이터는 메모리 내에서 바로 이어집니다(기술적으로는 실장은 마음대로 할 수 있지만 그 이외의 작업은 무모합니다).따라서 배열의 어딘가를 가리키는 참조는 있을 수 없습니다.

C 포인터에서는 임의의 장소와 임의의 장소를 가리키며 배열의 중앙을 가리킬 수 있습니다.하지만 안전하게 캐스팅하거나 어레이의 길이를 확인할 수 없습니다.D에서 포인터는 메모리 블록과 길이로의 오프셋을 포함하고 있습니다(또는 마지막에 대한 포인터는 실장이 실제로 무엇을 하는지 기억할 수 없습니다).이를 통해 D는 어레이를 슬라이스할 수 있습니다.C++에서는 시작과 끝을 가리키는 두 개의 반복기가 있지만 C++는 이와 같이 약간 이상합니다.

Java로 돌아가면 안됩니다.전술한 바와 같이 NIO는ByteBuffer그럼 어레이를 랩하고 슬라이스를 할 수 있지만 인터페이스가 어색합니다.물론 복사할 수 있습니다. 생각보다 훨씬 빠를 수 있습니다.자기 소개도 할 수 있고String- 어레이를 슬라이스할 수 있는 추상화(현재 Sun의 구현)와 같습니다.String 가지고 있다char[]와 시작 및 에는 "시작 오프셋 및 길이"가 있습니다.char[]byte[]낮은 레벨이지만, 클래스 베이스의 추상화를 적용하면, JDK7(아마도)까지 구문을 엉망으로 만들 것입니다.

@unique72 answer는 단순한 함수 또는 행으로 응답합니다.오브젝트를 '슬라이스'하고 싶은 클래스 타입으로 치환해야 할 수 있습니다.다양한 요구에 맞게 두 가지 변형이 제공됩니다.

/// Extract out array from starting position onwards
public static Object[] sliceArray( Object[] inArr, int startPos ) {
    return Arrays.asList(inArr).subList(startPos, inArr.length).toArray();
}

/// Extract out array from starting position to ending position
public static Object[] sliceArray( Object[] inArr, int startPos, int endPos ) {
    return Arrays.asList(inArr).subList(startPos, endPos).toArray();
}

★★★★★★★★★★★★★★★List★★★★★★★★★★★★★★★★★?

List<Byte> getSubArrayList(byte[] array, int offset, int size) {
   return new AbstractList<Byte>() {
      Byte get(int index) {
         if (index < 0 || index >= size) 
           throw new IndexOutOfBoundsException();
         return array[offset+index];
      }
      int size() {
         return size;
      }
   };
}

(테스트되지 않음)

어레이의 끝부분을 반복해야 했기 때문에 어레이를 복사하고 싶지 않았습니다.내 접근법은 배열 위에서 Itable로 만드는 것이었다.

public static Iterable<String> sliceArray(final String[] array, 
                                          final int start) {
  return new Iterable<String>() {
    String[] values = array;
    int posn = start;

    @Override
    public Iterator<String> iterator() {
      return new Iterator<String>() {
        @Override
        public boolean hasNext() {
          return posn < values.length;
        }

        @Override
        public String next() {
          return values[posn++];
        }

        @Override
        public void remove() {
          throw new UnsupportedOperationException("No remove");
        }
      };
    }
  };
}

이것은 Arrays.copyOfRange보다 조금 가볍습니다.범위 없음 또는 음수입니다.

public static final byte[] copy(byte[] data, int pos, int length )
{
    byte[] transplant = new byte[length];

    System.arraycopy(data, pos, transplant, 0, length);

    return transplant;
}

언급URL : https://stackoverflow.com/questions/1100371/grab-a-segment-of-an-array-in-java-without-creating-a-new-array-on-heap

반응형