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  
}