web-dev-qa-db-ja.com

データをコピーせずにJavaで配列のサブ配列を取得する方法は?

バッファに読み込まれているデータを操作するクラスのライブラリがいくつかあります。配列を何度も何度もコピーすることを避けて、データの一部をより深く処理メソッドに渡すことは可能ですか?それは奇妙に聞こえますが、私の特定のケースでは、データをブロックに分割して別々の場所に個別に書き込む特別なライターがあります。したがって、System.arraycopyを実行し、必要なものを取得し、その新しいサブ配列。そして、これは何度も起こります。そのようなコードをリファクタリングする最良の方法は何ですか?

46

Javaの多くのクラスは、配列のサブセットをパラメーターとして受け入れます。例:Writer.write(char cbuf []、int off、int len)。おそらく、これはユースケースに十分です。

21
Markus Kull
Arrays.asList(array).subList(x, y).

このメソッドは配列ではなく、Listを提供します。これははるかに柔軟です。

63
Ricky Clarkson

Javaでコピーせずにデータをラップして実際のarraを受信する yの実際の方法はありません。既存のメモリ上に新しい配列を作成することはできません。基本的に2つのオプションがあります。

  • 配列の範囲を受け入れることができるメソッドを使用します。これはすでに推奨されていました。
  • 配列に近い、多くのアプリケーションに適したある種の抽象化を提供するラッパーを使用します。以下に説明します。

_Java.nio.Buffer_クラス階層、特に_Java.nio.ByteBuffer_を使用できます。これは、配列全体またはサブ範囲でのバッファーの抽象化を提供します。多くの場合、それは人々が必要とするものです。これは、「ゼロコピー」フリップや柔軟なバイト領域表現など、多くの興味深い機能も提供します。

_Java.nio.ByteBuffer_ を使用したラッピングの例を次に示します。これは必要なものに非常に近いはずです。少なくとも一部の操作では。

_byte [] a1 = {0, 0, 1, 0};
ByteBuffer buf = ByteBuffer.wrap(a1,1,2);
_

その後、buf任意のByteBuffer操作で実行できます。

警告です。buf.array()は、すべての要素を含む元の_a1_配列(バックエンド)を返します。

10

Byte []のような組み込み配列を使用する場合、Javaでサブ配列を宣言する方法はありません。理由は次のとおりです。配列の長さは、したがって、データをコピーしないサブアレイには、長さを格納できる場所がありません!そのため、基本型には前述の効率的なバイト配列コピーを使用でき、上位型(リスト)には使用可能なメソッドがあります。

4
Joachim

Stringクラスが取るのと同じアプローチを取ることができます。配列、開始オフセット、およびサブ配列へのアクセスを提供する終了オフセットから構成される不変オブジェクトのクラスを作成します。このようなオブジェクトのユーザーは、配列全体またはサブ配列の違いを知る必要はありません。コンストラクタは配列をコピーする必要はなく、配列参照とその境界を保存するだけです。

2
rsp

あなたは(ArrayList).subList(value1、value2)i beliveを使用できますが、おそらくあなたの場合に役立つでしょうか? ArrayListを使用する場合はもちろんです。

1
Kotten

おそらく、配列を使用する代わりに、C#のArraySegmentと同様に、データをコピーするのではなく、元の配列のスライスへの参照を保持する別の型を使用する必要があります。これに対する追加の利点は、新しいインスタンスを作成せずに、必要に応じて元のアレイ上でスライスをシフトできることです。擬似コード:

public class ArraySegment<T> implements Iterable<T> 
{
      private int from, to;
      private T[] original;

      public ArraySegment<T>(T[] original, int from, int to)
      {
          //constructor stuff
      }

      public T get(int index)
      {
           return source[index + from];
      }

      public int size()
      {
          return to - from + 1;
      }

      @Override
      public Iterator<T> iterator()
      {
          //Iterator that iterates over the slice
      }

      //Can support setters on from/to variables
}
0
Orestis P.