Java: как передать byte[] по ссылке?
вы можете сделать это в .NET, используя ключевое слово "ref". Есть ли способ сделать это в Java?
3 ответов
что вы делаете в вашем методе? Если вы просто заполняете существующий массив, вам не нужна семантика pass-by-reference - ни в .NET, ни в Java. В обоих случаях ссылка будет передаваться по значению-поэтому изменения в объект будет виден вызывающим абонентом. Это то же самое, что сказать кому - то адрес своего дома и попросить их доставить что-то ему-без проблем.
если вы действительно хотите семантику pass-by-reference, т. е. абонент будет видеть любые изменения, внесенные в сам параметр, например, установив его в null или ссылку на другой массив байтов, то любой метод должен возвращать новое значение, или вам нужно передать ссылку на какой-то "держатель", который содержит ссылку на массив байтов, которые могут иметь (возможно, измененные) ссылка выхватил из его позже.
другими словами, если ваш метод выглядит так:
public void doSomething(byte[] data)
{
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
}
тогда ты в порядке. Если ваш метод выглядит так это:
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;
}
}
тогда вам нужно изменить его на либо:
public byte[] createArray(int length)
{
byte[] data = new byte[length];
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
return data;
}
или:
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;
}
}
подробнее параметр, передаваемый в C# и передача параметров в Java. (Боюсь, первое написано лучше, чем второе. Когда-нибудь я займусь обновлением.)
на самом деле, на Java,ссылки передаются по значению.
в этом случае ссылка является это.
может показаться, что создать новый byte
массив modifyArray
метод, что длина byte
массив по возвращаясь к main
метод 16
, однако, запуск этой программы показывает что-то другое:
Before Method: Length: 8
Method Entry: Length: 8
Method Exit: Length: 16
After Method: Length: 8
длина byte
массив по возвращении из modifyArray
способ возвращается к 8
вместо 16
.
почему это?
вот так main
метод называется modifyArray
метод и отправлено Копировать ссылку на new byte[8]
С помощью pass-by-value. Затем modifyArray
способ выбросил скопированную ссылку, создав new byte[16]
. К тому времени, как мы уйдем modifyArray
ссылка new byte[16]
выходит за рамки (и в конечном итоге будет собран мусор.) Однако main
метод по-прежнему имеет ссылку на new byte[8]
как только отправил скопированную ссылку, а не фактическая ссылка на ссылку.
это должно продемонстрировать, что Java передаст ссылку, используя pass-by-value.
Java использует pass by value для аргументов метода.
- примитивы (int, boolean и т. д.) являются частными случаями в Java.. не объекты как таковые. В этом случае в функцию передается копия примитива (аргумент). Это хорошо согласуется с теорией ценности pass by.
- для объектов, происходит то, что ссылка на объект передается по значению (копия сделана ссылка, а не объект)... но обе ссылки указывают к тому же объекту. Поэтому, если вы измените параметр объекта в методе, фактический объект будет изменен.
эта статья должна помочь вам.. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
что касается вопроса OP, просто передайте ссылку на массив byte[] методу. Чистый результат будет аналогичен pass by reference. Если вы измените массив байтов, вызывающий объект сможет увидеть изменения после выполнения метода.
обновление для подавления сопротивления :) => указывает на выход
.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
минорные моды reqd: используйте hashCode () и + для объединения строк в счетчике.Ява...
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
}