Java: Como passar byte [] por referência?
-
22-07-2019 - |
Pergunta
Você pode fazer isso no .NET usando a palavra -chave "ref". Existe alguma maneira de fazê -lo em Java?
Solução
O que você está fazendo em seu método? Se você está apenas preenchendo uma matriz existente, não precisa de semântica de passagem por referência-no .NET ou no Java. Nos dois casos, a referência será passada por valor - portanto, mudanças no objeto será visível pelo chamador. É como dizer a alguém o endereço da sua casa e pedir que eles entregassem algo a ela - sem problemas.
Se você verdade Deseja semântica de passagem por referência, ou seja, o chamador verá quaisquer alterações feitas no próprio parâmetro, por exemplo, definindo-o como nulo ou uma referência a uma matriz de bytes diferente, então qualquer método precisa retornar o novo valor ou você precisa passar Uma referência a algum tipo de "suporte" que contém uma referência à matriz de bytes, e que pode ter a referência (possivelmente alterada) capturada mais tarde.
Em outras palavras, se o seu método parece gostar disso:
public void doSomething(byte[] data)
{
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
}
Então você está bem. Se o seu método se parece com o seguinte:
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;
}
}
Então você precisa alterá -lo para:
public byte[] createArray(int length)
{
byte[] data = new byte[length];
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
return data;
}
ou:
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;
}
}
Para mais detalhes, leia Parâmetro Passando em C# e Parâmetro Passando em Java. (O primeiro é melhor escrito que o último, receio. Um dia vou fazer uma atualização.)
Outras dicas
Na verdade, em Java, o As referências são passadas por valor.
Nesse caso, a referência é um byte[]
objeto. Quaisquer alterações que afetem o objeto em si serão vistas do método do chamador.
No entanto, se você tentar substituir a referência, por exemplo, usando new byte[length]
, você está apenas substituindo a referência que obteve por valor por valor, para não estar alterando a referência no método do chamador.
Aqui está uma leitura interessante sobre esta edição: Java é damita de passe por valor!
Aqui está um exemplo 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);
}
}
Este programa criará um byte
Matriz de comprimento 8
no main
método, que chamará o modifyArray
método, onde o novo byte
Matriz de comprimento 16
é criado.
Pode parecer que, criando um novo byte
Array no modifyArray
método, que o comprimento do byte
Array ao retornar ao main
Método será 16
, no entanto, a execução deste programa revela algo diferente:
Before Method: Length: 8
Method Entry: Length: 8
Method Exit: Length: 16
After Method: Length: 8
O comprimento do byte
Array ao retornar do modifyArray
método reverte para 8
ao invés de 16
.
Por que é que?
Isso é porque o main
Método chamado modifyArray
método e enviado uma referência copiada ao new byte[8]
usando Pass-por valor. Então o modifyArray
método jogou fora a referência copiada criando um new byte[16]
. Quando saímos modifyArray
, a referência ao new byte[16]
está fora de escopo (e eventualmente será coletado de lixo.) No entanto, o main
o método ainda tem referência ao new byte[8]
apenas como isso enviou a referência copiada e não uma referência real à referência.
Isso deve demonstrar que o Java passará a referência usando o valor por passes.
Java usa o passe por valor para argumentos de método.
- Primitivos (int, booleano, etc.) são casos especiais em java .. não objetos em si. Nesse caso, uma cópia do primitivo (argumento) é transmitida para a função. Isso goma bem com o passe pela teoria do valor.
- Para objetos, o que acontece é que o ref para o objeto é passado pelo valor (uma cópia da referência é feita e não o objeto) ... mas ambas as referências apontam para o mesmo objeto. Portanto, se você modificar um parâmetro de objeto em um método, o objeto real será modificado.
Este artigo deve ajudá -lo ..http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-sass.html
Quanto à pergunta do OP, basta passar na referência à matriz de byte [] ao método. O resultado líquido seria semelhante a passar por referência. Se você modificar a matriz de bytes, o chamador poderá ver a execução do método post de alterações.
Atualizar para reprimir a resistência :) => indica saída
.NET TERRA
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
}
Terra java
Menores menores reqd: use hashcode () e + para concatar strings em contador.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
}