web-dev-qa-db-fra.com

Comment obtenir un sous-tableau de tableau en Java, sans copier de données?

J'ai une bibliothèque de classes, travaillant avec mes données, qui est lue dans le tampon. Est-il possible, d'une manière ou d'une autre, d'éviter de copier des tableaux encore et encore, en passant de plus en plus de parties de données dans les méthodes de traitement? Eh bien, cela semble étrange, mais dans mon cas particulier, il y a un écrivain spécial, qui divise les données en blocs et les écrit individuellement dans différents emplacements, donc il exécute simplement System.arraycopy, obtient ce dont il a besoin et appelle l'écrivain sous-jacent, avec cette nouvelle sous-tableau. Et cela arrive plusieurs fois. Quelle est la meilleure approche pour refactoriser un tel code?

46
Illarion Kovalchuk

De nombreuses classes de Java acceptent un sous-ensemble de tableaux comme paramètre. Par exemple Writer.write (char cbuf [], int off, int len). Peut-être que cela suffit déjà pour votre cas d'utilisation.

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

Cette méthode ne vous donne pas un tableau, mais un List, qui est beaucoup plus flexible.

63
Ricky Clarkson

Il n'y a aucun moyen réel d'envelopper des données sans les copier et de recevoir l'arra réel y en Java. Vous ne pouvez tout simplement pas créer un nouveau tableau sur la mémoire existante. Vous avez essentiellement 2 options:

  • Utilisez des méthodes qui peuvent accepter une plage de tableaux. C'était déjà recommandé.
  • Utilisez un wrapper qui donne une sorte d'abstraction proche du tableau et qui convient à de nombreuses applications. Sera décrit ci-dessous.

Vous pouvez utiliser la hiérarchie des classes Java.nio.Buffer, En particulier Java.nio.ByteBuffer Qui offre une abstraction de tampon sur un tableau entier ou des sous-plages. C'est souvent ce dont les gens ont besoin. Cela offre également de nombreuses capacités intéressantes comme le flip "zéro copie" et la représentation flexible de la zone d'octets.

Voici un exemple d'encapsulation utilisant Java.nio.ByteBuffer . Cela devrait être très proche de ce dont vous avez besoin. Au moins pour certaines opérations.

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

Ensuite, vous pouvez faire sur buf toute opération ByteBuffer.

Juste un avertissement, buf.array() renvoie le tableau a1 D'origine (backend) avec tous les éléments.

10

Il n'y a aucun moyen de déclarer un sous-tableau dans Java si vous utilisez des tableaux intégrés comme l'octet []. La raison en est: la longueur du tableau est stockée avec les données, pas avec la déclaration de Par conséquent, un sous-tableau qui ne copie pas les données n'a aucun endroit où il peut stocker la longueur! Ainsi, pour les types de base, vous pouvez utiliser les copies de tableau d'octets efficaces mentionnées et pour les types supérieurs (Liste), il existe des méthodes disponibles.

4
Joachim

Vous pouvez adopter la même approche que la classe String; créer une classe pour les objets immuables qui sont construits à partir d'un tableau, un décalage de début et un décalage de fin qui offre un accès au sous-tableau. L'utilisateur d'un tel objet n'a pas à connaître la distinction entre l'ensemble du tableau ou un sous-tableau. Le constructeur n'a pas à copier le tableau, il suffit de stocker la référence du tableau et ses limites.

2
rsp

Vous pourriez utiliser (ArrayList) .subList (value1, value2) je crois, cela pourrait peut-être vous aider dans votre cas? C'est bien sûr si vous souhaitez utiliser une ArrayList.

1
Kotten

Peut-être qu'au lieu de travailler avec des tableaux, vous devriez travailler avec un type différent qui conserve une référence à une tranche du tableau d'origine, au lieu de copier les données, similaire à ArraySegment en C #. Un avantage supplémentaire est que vous pouvez également déplacer la tranche sur la baie d'origine à la demande, sans créer de nouvelles instances. Pseudo code:

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.