Java: come passare byte [] per riferimento?
-
22-07-2019 - |
Domanda
Puoi farlo in .NET usando la parola chiave " ref " ;. C'è un modo per farlo in Java?
Soluzione
Cosa stai facendo nel tuo metodo? Se stai semplicemente popolando un array esistente, non hai bisogno della semantica pass-by-reference - sia in .NET che in Java. In entrambi i casi, il riferimento verrà passato per valore, quindi le modifiche all'oggetto saranno visibili al chiamante. È come dire a qualcuno l'indirizzo di casa tua e chiedere loro di consegnargli qualcosa - nessun problema.
Se veramente desideri una semantica pass-by-reference, ovvero il chiamante vedrà tutte le modifiche apportate al parametro stesso, ad es. impostandolo su null o su un riferimento a un array di byte diverso, entrambi i metodi devono restituire il nuovo valore oppure è necessario passare un riferimento a una sorta di "titolare" che contiene un riferimento all'array di byte e che può essere acquisito in seguito dal riferimento (eventualmente modificato).
In altre parole, se il tuo metodo è simile a questo:
public void doSomething(byte[] data)
{
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
}
allora stai bene. Se il tuo metodo è simile al seguente:
public void createArray(byte[] data, int length)
{
// Eek! Change to parameter won't get seen by caller
data = new byte[length];
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
}
quindi è necessario modificarlo in:
public byte[] createArray(int length)
{
byte[] data = new byte[length];
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
return data;
}
o
public class Holder<T>
{
public T value; // Use a property in real code!
}
public void createArray(Holder<byte[]> holder, int length)
{
holder.value = new byte[length];
for (int i=0; i < length; i++)
{
holder.value[i] = (byte) i;
}
}
Per maggiori dettagli, leggi Parametro che passa in C # e Parametro che passa in Java . (Il primo è scritto meglio del secondo, temo. Un giorno mi metto in giro per fare un aggiornamento.)
Altri suggerimenti
In realtà, in Java, i riferimenti sono passati per valore .
In questo caso, il riferimento è un oggetto byte []
. Eventuali modifiche che interessano l'oggetto stesso verranno visualizzate dal metodo chiamante.
Tuttavia, se si tenta di sostituire il riferimento, ad esempio utilizzando new byte [lunghezza]
, si sostituisce solo il riferimento ottenuto per valore pass-by, quindi non si sta cambiando il riferimento nel metodo chiamante.
Ecco una lettura interessante su questo problema: Java è un valore pass-by-value!
Ecco un esempio concreto:
public class PassByValue
{
public static void modifyArray(byte[] array)
{
System.out.println("Method Entry: Length: " + array.length);
array = new byte[16];
System.out.println("Method Exit: Length: " + array.length);
}
public static void main(String[] args)
{
byte[] array = new byte[8];
System.out.println("Before Method: Length: " + array.length);
modifyArray(array);
System.out.println("After Method: Length: " + array.length);
}
}
Questo programma creerà un byte
di lunghezza 8
nel metodo main
, che chiamerà editArray
metodo, in cui viene creato un nuovo array byte
di lunghezza 16
.
Potrebbe sembrare che creando un nuovo array byte
nel metodo editArray
, che la lunghezza dell'array byte
al ritorno al Il metodo main
sarà 16
, tuttavia, l'esecuzione di questo programma rivela qualcosa di diverso:
Before Method: Length: 8
Method Entry: Length: 8
Method Exit: Length: 16
After Method: Length: 8
La lunghezza dell'array byte
al ritorno dal metodo editArray
ritorna a 8
anziché 16
.
Perché?
Questo perché il metodo main
ha chiamato il metodo editArray
e ha inviato un riferimento copiato al new byte [8]
utilizzando pass-by-value . Quindi, il metodo changeArray
ha eliminato il riferimento copiato creando un nuovo byte [16]
. Quando lasciamo editArray
, il riferimento al new byte [16]
non rientra nell'ambito di applicazione (e alla fine verrà spazzato via.) Tuttavia, il main
fa ancora riferimento al nuovo byte [8]
poiché solo ha inviato il riferimento copiato e non un riferimento effettivo al riferimento.
Ciò dovrebbe dimostrare che Java passerà il riferimento usando il valore pass-by.
Java utilizza il valore passa per valore per gli argomenti del metodo .
- Primitives (int, boolean, ecc. .) sono casi speciali in Java .. non oggetti di per sé. In questo caso, una copia della primitiva (argomento) viene passata nella funzione. Questo si gelifica bene con la teoria del passaggio per valore.
- Per Oggetti, ciò che accade è che il riferimento all'oggetto viene passato per valore (viene fatta una copia del riferimento anziché l'oggetto) ... ma entrambi i riferimenti puntano allo stesso oggetto. Pertanto, se si modifica un parametro oggetto in un metodo, l'oggetto reale verrà modificato.
Questo articolo dovrebbe aiutarti .. http://www.javaworld.com/ JavaWorld / javaqa / 2000-05 / 03-qa-0526-pass.html
Per quanto riguarda la domanda dell'OP, basta passare il riferimento all'array byte [] al metodo. Il risultato netto sarebbe simile al passaggio per riferimento. Se si modifica l'array di byte, il chiamante sarà in grado di vedere le modifiche dopo l'esecuzione del metodo.
Aggiorna per reprimere la resistenza :) = > indica l'output
.NET Land
class Counter
{
private int m_count = 0;
public override string ToString()
{
return String.Format("Counter ID{0} : Value {1}", this.GetHashCode(), m_count);
}
public void Increment()
{ m_count++; }
}
class MakeAPass
{
public void PassByValueAndModify(int i)
{ i = 20; }
public void PassByRefAndModify(ref int i)
{ i = 20; }
public void PassByValueAndModify(Counter c)
{ c.Increment(); }
public void PassByRefAndModify(ref Counter c)
{ c.Increment(); }
public void PassByRefAndReassign(ref Counter c)
{
c = new Counter();
for (int i=0; i<5; ++i)
c.Increment();
}
}
static void Main(string[] args)
{
MakeAPass obj = new MakeAPass();
int intVal = 10;
obj.PassByValueAndModify(intVal);
Console.WriteLine(intVal); // => 10
obj.PassByRefAndModify(ref intVal);
Console.WriteLine(intVal); // => 20
Counter obCounter = new Counter();
obj.PassByValueAndModify(obCounter);
Console.WriteLine(obCounter.ToString()); // => Counter ID58225482 : Value 1
obj.PassByRefAndModify(ref obCounter);
Console.WriteLine(obCounter.ToString()); // => Counter ID58225482 : Value 2
obj.PassByRefAndReassign(ref obCounter);
Console.WriteLine(obCounter.ToString()); // => Counter ID54267293 : Value 5
}
Java Land
Mods minori reqd: usa hashCode () e + per concatenare le stringhe in Counter.java ...
class MakeAPass
{
public void PassByValueAndModify(int i)
{ i = 20; }
// can't be done.. Use Integer class which wraps primitive
//public void PassByRefAndModify(ref int i)
public void PassByValueAndModify(Counter c)
{ c.Increment(); }
// same as above. no ref keyword though
//public void PassByRefAndModify(ref Counter c)
// this can't be done as in .net
//public void PassByRefAndReassign(ref Counter c)
public void PassAndReassign(Counter c)
{
c = new Counter();
for (int i=0; i<5; ++i)
c.Increment();
}
}
public static void main(String args[])
{
MakeAPass obj = new MakeAPass();
int intVal = 10;
obj.PassByValueAndModify(intVal);
System.out.println(intVal); // => 10
//obj.PassByRefAndModify(ref intVal);
//System.out.println(intVal); // can't get it to say 20
Counter obCounter = new Counter();
obj.PassByValueAndModify(obCounter);
System.out.println(obCounter.ToString()); // => Counter ID3541984 : Value 1
//obj.PassByRefAndModify(ref obCounter);
//Console.WriteLine(obCounter.ToString()); // no ref. but can make it 2 by repeating prev call
obj.PassAndReassign(obCounter);
System.out.println(obCounter.ToString()); // => Counter ID3541984 : Value 1
// can't get it to say 5
}