Ich suche nach einer Methode in Java, die ein Segment eines Arrays zurückgibt. Ein Beispiel wäre, das Byte-Array zu erhalten, das das 4. und 5. Byte eines Byte-Arrays enthält. Ich möchte dafür kein neues Byte-Array im Heap-Speicher erstellen müssen. Im Moment habe ich folgenden Code:
doSomethingWithTwoBytes(byte[] twoByteArray);
void someMethod(byte[] bigArray)
{
byte[] x = {bigArray[4], bigArray[5]};
doSomethingWithTwoBytes(x);
}
Ich würde gerne wissen, ob es eine Möglichkeit gibt, beispielsweise zu tun, doSomething(bigArray.getSubArray(4, 2))
wo 4 der Versatz und 2 die Länge ist.
Antworten:
Haftungsausschluss: Diese Antwort entspricht nicht den Einschränkungen der Frage:
( Ehrlich gesagt, ich denke, meine Antwort ist es wert, gelöscht zu werden. Die Antwort von @ unique72 ist korrekt. Imma, lass diese Bearbeitung ein bisschen stehen und dann werde ich diese Antwort löschen. )
Ich kenne keine Möglichkeit, dies direkt mit Arrays ohne zusätzliche Heap-Zuordnung zu tun, aber die anderen Antworten, die einen Unterlisten-Wrapper verwenden, haben nur eine zusätzliche Zuordnung für den Wrapper - aber nicht für das Array -, was im Fall von nützlich wäre ein großes Array.
Wenn man jedoch nach Kürze sucht, wurde die Dienstprogrammmethode
Arrays.copyOfRange()
in Java 6 eingeführt (Ende 2006?):quelle
copyOfRange
. Wenn es Closed-Source wäre, hätte es vielleicht vorbei sein können. :)Arrays.asList(myArray)
delegiert an newArrayList(myArray)
, wodurch das Array nicht kopiert, sondern nur die Referenz gespeichert wird. Wenn SieList.subList(start, end)
danach verwenden, wird a erstellt,SubList
das nur auf die ursprüngliche Liste verweist (die immer noch nur auf das Array verweist). Kein Kopieren des Arrays oder seines Inhalts, nur das Erstellen eines Wrappers, und alle beteiligten Listen werden vom ursprünglichen Array unterstützt. (Ich dachte, es wäre schwerer.)quelle
Arrays
verwirrend aufgerufen wirdArrayList
, aber tatsächlichList
ein Array umgibt, im Gegensatz dazujava.util.ArrayList
eine Kopie erstellen würde. Keine neuen Zuordnungen (des Inhalts der Liste) und keine Abhängigkeiten von Dritten. Dies ist meines Erachtens die richtigste Antwort.byte[]
in seinem Fall). Alles was du bekommst wäreList<byte[]>
. Ein Wechselbyte[] bigArray
zu kannByte[] bigArray
möglicherweise einen erheblichen Speicheraufwand verursachen.sun.misc.Unsafe
Klasse.Wenn Sie einen Aliasing-Ansatz im Zeigerstil suchen, damit Sie nicht einmal Speicherplatz zuweisen und die Daten kopieren müssen, haben Sie meines Erachtens kein Glück.
System.arraycopy()
wird von Ihrer Quelle zum Ziel kopiert, und für dieses Dienstprogramm wird Effizienz beansprucht. Sie müssen das Zielarray zuweisen.quelle
array*copy*()
derselbe Speicher wiederverwendet werden? Ist das nicht genau das Gegenteil von dem, was ein Anrufer erwarten würde?Eine Möglichkeit besteht darin, das Array einzuschließen
java.nio.ByteBuffer
einzuschließen, die absoluten Put / Get-Funktionen zu verwenden und den Puffer in Scheiben zu schneiden, um an einem Subarray zu arbeiten.Zum Beispiel:
Beachten Sie, dass Sie beide aufrufen müssen
wrap()
undslice()
, da siewrap()
nur die relativen Put / Get-Funktionen betreffen, nicht die absoluten.ByteBuffer
kann etwas schwierig zu verstehen sein, ist aber höchstwahrscheinlich effizient implementiert und es lohnt sich zu lernen.quelle
StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buffer, 0, readBytes))
Arrays.copyOfRange
?Arrays.copyOfRange
ist wahrscheinlich effizienter. Im Allgemeinen müssten Sie für Ihren spezifischen Anwendungsfall messen.Verwenden Sie java.nio.Buffer's. Es ist ein leichter Wrapper für Puffer verschiedener primitiver Typen und hilft bei der Verwaltung von Slicing, Position, Konvertierung, Bytereihenfolge usw.
Wenn Ihre Bytes aus einem Stream stammen, können die NIO-Puffer den "Direktmodus" verwenden, der einen Puffer erstellt, der von nativen Ressourcen unterstützt wird. Dies kann in vielen Fällen die Leistung verbessern.
quelle
Sie können ArrayUtils.subarray in Apache Commons verwenden. Nicht perfekt, aber etwas intuitiver als
System.arraycopy.
Der Nachteil ist, dass es eine weitere Abhängigkeit in Ihren Code einführt.quelle
Ich sehe, dass die Antwort auf die Unterliste bereits hier ist, aber hier ist der Code, der zeigt, dass es sich um eine echte Unterliste handelt, nicht um eine Kopie:
Ich glaube jedoch nicht, dass es eine gute Möglichkeit gibt, dies direkt mit Arrays zu tun.
quelle
quelle
Eine Möglichkeit wäre, das gesamte Array sowie die Start- und Endindizes zu übergeben und zwischen diesen zu iterieren, anstatt über das gesamte übergebene Array zu iterieren.
quelle
Mit den
List
s können SiesubList
etwas transparent verwenden und damit arbeiten . Bei primitiven Arrays müssen Sie eine Art Offset-Limit verfolgen.ByteBuffer
s haben ähnliche Optionen wie ich gehört habe.Bearbeiten: Wenn Sie für die nützliche Methode verantwortlich sind, können Sie sie einfach mit Grenzen definieren (wie bei vielen Array-bezogenen Methoden in Java selbst:
Es ist jedoch nicht klar, ob Sie an den Array-Elementen selbst arbeiten, z. B. etwas berechnen und das Ergebnis zurückschreiben?
quelle
Java-Referenzen verweisen immer auf ein Objekt. Das Objekt hat eine Kopfzeile, die unter anderem den konkreten Typ identifiziert (so dass Casts mit fehlschlagen können
ClassCastException
). Bei Arrays enthält der Start des Objekts auch die Länge, die Daten folgen unmittelbar danach im Speicher (technisch gesehen kann eine Implementierung frei tun, was sie will, aber es wäre dumm, etwas anderes zu tun). Sie können also keine Referenz haben, die irgendwo in ein Array zeigt.In C zeigen Zeiger überall und auf alles, und Sie können auf die Mitte eines Arrays zeigen. Sie können jedoch nicht sicher umwandeln oder herausfinden, wie lang das Array ist. In D enthält der Zeiger einen Versatz in den Speicherblock und die Länge (oder gleichwertig einen Zeiger auf das Ende, ich kann mich nicht erinnern, was die Implementierung tatsächlich tut). Dies ermöglicht es D, Arrays zu schneiden. In C ++ hätten Sie zwei Iteratoren, die auf den Anfang und das Ende zeigen, aber C ++ ist so etwas seltsam.
Zurück zu Java, nein, das kannst du nicht. Wie bereits erwähnt,
ByteBuffer
können Sie mit NIO ein Array umbrechen und dann in Scheiben schneiden, erhalten jedoch eine umständliche Oberfläche. Sie können natürlich kopieren, was wahrscheinlich sehr viel schneller ist, als Sie denken würden. Sie können Ihre eigeneString
ähnliche Abstraktion einführen , mit der Sie ein Array in Scheiben schneiden können (die aktuelle Sun-Implementierung vonString
hat einechar[]
Referenz plus Startversatz und Länge, eine leistungsstärkere Implementierung hat nur diechar[]
).byte[]
ist auf niedrigem Niveau, aber jede klassenbasierte Abstraktion, die Sie anwenden, wird die Syntax bis JDK7 (vielleicht) schrecklich durcheinander bringen.quelle
substring
in HotSpot weiter (vergessen Sie, welcher Build dies geändert hat). Warum sollte JDK7 eine bessere Syntax als ByteBuffer zulassen?[]
Notation für benutzerdefinierte Typen wieList
und zulassenByteBuffer
.@ unique72 Antwort als einfache Funktion oder Zeile müssen Sie möglicherweise Object durch den entsprechenden Klassentyp ersetzen, den Sie in Scheiben schneiden möchten. Es werden zwei Varianten angegeben, um unterschiedlichen Anforderungen gerecht zu werden.
quelle
Wie wäre es mit einer dünnen
List
Hülle?(Ungetestet)
quelle
Byte
Objekte für allebyte
Werte zwischengespeichert. Der Boxaufwand sollte also eher langsam sein.Ich musste das Ende eines Arrays durchlaufen und wollte das Array nicht kopieren. Mein Ansatz war es, ein Iterable über das Array zu erstellen.
quelle
Dies ist etwas leichter als Arrays.copyOfRange - kein Bereich oder negativ
quelle