Вы можете сделать это в .NET с помощью ключевого слова ref. Есть ли способ сделать это на Java?
Java: Как передать байт [] по ссылке?
Ответ 1
Что вы делаете в своем методе? Если вы просто заполняете существующий массив, вам не нужна семантика передачи по ссылке - либо в .NET, либо на Java. В обоих случаях эта ссылка будет передана по значению - поэтому изменения объекта будут видны вызывающей стороне. Это как рассказывать кому-то адрес вашего дома и просить их что-то доставить - никаких проблем.
Если вам действительно нужна семантика передачи по ссылке, то есть вызывающий объект увидит любые изменения, внесенные в сам параметр, например. установив его на нуль или ссылку на другой массив байтов, тогда либо метод должен вернуть новое значение, либо вам нужно передать ссылку на какой-то "держатель", который содержит ссылку на массив байтов, и который может иметь (возможно, измененная) ссылка схватила его позже.
Другими словами, если ваш метод выглядит так:
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;
}
}
Для получения дополнительной информации прочитайте Передача параметров в С# и Передача параметров в Java. (Пожалуй, первое из них написано лучше, чем последнее.) Однажды я перейду к обновлению.)
Ответ 2
Собственно, в Java ссылки передаются по значению.
В этом случае ссылка является объектом byte[]
. Любые изменения, которые влияют на сам объект, будут видны из метода вызывающего абонента.
Однако, если вы попытаетесь заменить ссылку, например, используя new byte[length]
, вы заменяете только ссылку, полученную вами по значению pass-by-value, поэтому вы не изменяете ссылку в методе вызова.
Вот интересный прочтение этой проблемы: Java - это пропускная способность Dammit!
Вот конкретный пример:
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);
}
}
Эта программа создаст массив byte
длины 8
в методе main
, который вызовет метод modifyArray
, где будет создан новый массив byte
длины 16
.
Может показаться, что, создав новый массив 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.
Ответ 3
Java использует pass by value для аргументов метода.
- Примитивы (int, boolean и т.д.) являются особыми случаями в Java.. не являются объектами как таковыми. В этом случае копия примитива (аргумента) передается в функцию. Это хорошо отражается на переходе по теории стоимости.
- Для объектов происходит то, что ref для объекта передается по значению (копия ссылки выполняется, а не объект)... но обе ссылки указывают на один и тот же объект. Поэтому, если вы изменяете параметр объекта в методе, фактический объект будет изменен.
Эта статья должна помочь вам. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
Что касается вопроса OP, просто передайте метод reference в массив byte []. Конечный результат будет аналогичен прохождению по ссылке. Если вы измените массив байтов, вызывающий сможет увидеть выполнение метода post post.
Обновление для подавления сопротивления:) = > указывает вывод
.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
Незначительные модификации: используйте hashCode() и + для concat строк в 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
}