Je recherche une méthode en Java qui retournera un segment d'un tableau. Un exemple serait d'obtenir le tableau d'octets contenant les 4e et 5e octets d'un tableau d'octets. Je ne veux pas avoir à créer un nouveau tableau d'octets dans la mémoire du tas juste pour le faire. En ce moment, j'ai le code suivant:
doSomethingWithTwoBytes(byte[] twoByteArray);
void someMethod(byte[] bigArray)
{
byte[] x = {bigArray[4], bigArray[5]};
doSomethingWithTwoBytes(x);
}
J'aimerais savoir s'il y avait un moyen de faire simplement doSomething(bigArray.getSubArray(4, 2))
où 4 est le décalage et 2 est la longueur, par exemple.
Réponses:
Avertissement: Cette réponse n'est pas conforme aux contraintes de la question:
( Honnêtement, je pense que ma réponse mérite d'être supprimée. La réponse de @ unique72 est correcte. Je vais laisser cette modification reposer un peu, puis je supprimerai cette réponse. )
Je ne connais pas de moyen de le faire directement avec des tableaux sans allocation de tas supplémentaire, mais les autres réponses utilisant un wrapper de sous-liste ont une allocation supplémentaire pour le wrapper uniquement - mais pas le tableau - ce qui serait utile dans le cas de un large éventail.
Cela dit, si l'on recherche la brièveté, la méthode utilitaire a
Arrays.copyOfRange()
été introduite dans Java 6 (fin 2006?):la source
copyOfRange
. S'il s'agissait de sources fermées, cela aurait peut-être pu passer. :)Arrays.asList(myArray)
délègue à newArrayList(myArray)
, qui ne copie pas le tableau mais stocke simplement la référence. UtiliserList.subList(start, end)
après cela fait unSubList
qui fait simplement référence à la liste d'origine (qui fait toujours référence au tableau). Pas de copie du tableau ou de son contenu, il suffit de créer un wrapper et toutes les listes impliquées sont sauvegardées par le tableau d'origine. (Je pensais que ce serait plus lourd.)la source
Arrays
appelé de manière confuseArrayList
, mais qui est vraiment unList
autour d'un tableau, par opposition àjava.util.ArrayList
ce qui ferait une copie. Pas de nouvelles allocations (du contenu de la liste) et pas de dépendances tierces. C'est, je crois, la réponse la plus correcte.byte[]
dans son cas). Tout ce que vous obtiendrez seraitList<byte[]>
. Et le passagebyte[] bigArray
àByte[] bigArray
pourrait imposer une surcharge de mémoire importante.sun.misc.Unsafe
classe.Si vous recherchez une approche d'alias de style pointeur, de sorte que vous n'ayez même pas besoin d'allouer de l'espace et de copier les données, je pense que vous n'avez pas de chance.
System.arraycopy()
copiera de votre source à destination, et l'efficacité est réclamée pour cet utilitaire. Vous devez allouer le tableau de destination.la source
array*copy*()
réutiliser la même mémoire? N'est-ce pas exactement le contraire de ce à quoi un appelant pourrait s'attendre?Une façon consiste à envelopper le tableau dans
java.nio.ByteBuffer
, d'utiliser les fonctions put / get absolues et de découper le tampon pour qu'il fonctionne sur un sous-tableau.Par exemple:
Notez que vous devez appeler les deux
wrap()
etslice()
, puisquewrap()
par lui-même n'affecte que les fonctions put / get relatives, pas les fonctions absolues.ByteBuffer
peut être un peu difficile à comprendre, mais il est très probablement mis en œuvre efficacement et mérite d'être appris.la source
StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buffer, 0, readBytes))
Arrays.copyOfRange
?Arrays.copyOfRange
est probablement plus efficace. En règle générale, vous devrez mesurer votre cas d'utilisation spécifique.Utilisez java.nio.Buffer. C'est un wrapper léger pour les tampons de divers types primitifs et aide à gérer le découpage, la position, la conversion, l'ordre des octets, etc.
Si vos octets proviennent d'un Stream, les tampons NIO peuvent utiliser le "mode direct" qui crée un tampon sauvegardé par des ressources natives. Cela peut améliorer les performances dans de nombreux cas.
la source
Vous pouvez utiliser ArrayUtils.subarray dans apache commons. Pas parfait mais un peu plus intuitif que
System.arraycopy.
l'inconvénient est qu'il introduit une autre dépendance dans votre code.la source
Je vois que la réponse à la sous-liste est déjà là, mais voici le code qui démontre que c'est une vraie sous-liste, pas une copie:
Cependant, je ne pense pas qu'il existe un bon moyen de le faire directement avec des tableaux.
la source
la source
Les
List
s vous permettent d'utiliser et de travailler avecsubList
quelque chose de manière transparente. Les tableaux primitifs vous obligeraient à suivre une sorte de limite de décalage.ByteBuffer
s ont des options similaires à celles que j'ai entendues.Edit: Si vous êtes en charge de la méthode utile, vous pouvez simplement la définir avec des limites (comme cela est fait dans de nombreuses méthodes liées aux tableaux dans Java lui-même:
Ce n'est pas clair, cependant, si vous travaillez sur les éléments du tableau eux-mêmes, par exemple si vous calculez quelque chose et écrivez le résultat?
la source
Une option serait de passer le tableau entier et les index de début et de fin, et de faire une itération entre ceux-ci au lieu d'itérer sur tout le tableau passé.
la source
Les références Java pointent toujours vers un objet. L'objet a un en-tête qui, entre autres, identifie le type de béton (les casts peuvent donc échouer avec
ClassCastException
). Pour les tableaux, le début de l'objet inclut également la longueur, les données suivent alors immédiatement après en mémoire (techniquement une implémentation est libre de faire ce qu'elle veut, mais il serait stupide de faire autre chose). Donc, vous pouvez; t avoir une référence qui pointe quelque part dans un tableau.En C, les pointeurs pointent n'importe où et vers n'importe quoi, et vous pouvez pointer vers le milieu d'un tableau. Mais vous ne pouvez pas lancer en toute sécurité ou découvrir la longueur de la matrice. En D, le pointeur contient un décalage dans le bloc de mémoire et la longueur (ou de manière équivalente un pointeur vers la fin, je ne me souviens pas de ce que fait réellement l'implémentation). Cela permet à D de découper des tableaux. En C ++, vous auriez deux itérateurs pointant vers le début et la fin, mais C ++ est un peu étrange comme ça.
Donc, pour revenir à Java, non, vous ne pouvez pas. Comme mentionné, NIO
ByteBuffer
vous permet d'envelopper un tableau puis de le découper, mais donne une interface peu pratique. Vous pouvez bien sûr copier, ce qui est probablement beaucoup plus rapide que vous ne le pensez. Vous pouvez introduire votre propreString
abstraction qui vous permet de découper un tableau (l'implémentation Sun actuelle deString
a unechar[]
référence plus un décalage de début et une longueur, une implémentation plus performante a juste lechar[]
).byte[]
est de bas niveau, mais toute abstraction basée sur les classes que vous mettez sur qui va faire un terrible désordre de la syntaxe, jusqu'à JDK7 (peut-être).la source
substring
dans HotSpot (oubliez quelle version a changé cela). Pourquoi dites-vous que JDK7 permettrait une meilleure syntaxe que ByteBuffer?[]
notation de tableau sur les types définis par l'utilisateur, tels queList
etByteBuffer
. Encore en attente ...@ unique72 answer comme une simple fonction ou ligne, vous devrez peut-être remplacer Object, par le type de classe respectif que vous souhaitez «découper». Deux variantes sont proposées pour répondre à divers besoins.
la source
Que diriez-vous d'un
List
emballage fin ?(Non testé)
la source
Byte
objets de toutes lesbyte
valeurs sont mis en cache. Les frais généraux de boxe devraient donc être assez lents.J'avais besoin d'itérer jusqu'à la fin d'un tableau et je ne voulais pas copier le tableau. Mon approche était de créer un Iterable sur le tableau.
la source
C'est un peu plus léger que Arrays.copyOfRange - pas de plage ou négatif
la source