Java: How to pass byte[] by reference?

前端 未结 3 390
伪装坚强ぢ
伪装坚强ぢ 2020-11-30 06:43

You can do it in .NET by using the keyword \"ref\". Is there any way to do so in Java?

相关标签:
3条回答
  • 2020-11-30 07:20

    Java uses pass by value for method arguments.

    • Primitives (int, boolean, etc.) are special cases in Java.. not objects per se. In this case, a copy of the primitive (argument) is passed into the function. This gels well with the pass by value theory.
    • For Objects, what happens is that the ref to the object is passed by value (a copy of the reference is made rather than the object)... but both references point to the same object. So if you modify an object parameter in a method, the actual object will be modified.

    This article should help you out.. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

    As for the OP's question, just pass in the reference to the byte[] array to the method. The net result would be similar to pass by reference. If you modify the byte array, the caller will be able to see the changes post method execution.

    Update to quell the resistance :) => indicates 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

    Minor mods reqd: Use hashCode() and + to concat strings 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  
    }
    
    0 讨论(0)
  • 2020-11-30 07:25

    Actually, in Java, the references are passed-by-value.

    In this case, the reference is a byte[] object. Any changes that affect the object itself will be seen from the caller method.

    However, if you try to replace the reference, for example using new byte[length], you are only replacing the reference that you obtained by pass-by-value, so you are not changing the reference in the caller method.

    Here's an interesting read about this issue: Java is Pass-by-Value Dammit!


    Here's an concrete example:

    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);
        }
    }
    

    This program will create a byte array of length 8 in the main method, which will call the modifyArray method, where the a new byte array of length 16 is created.

    It may appear that by creating a new byte array in the modifyArray method, that the length of the byte array upon returning to the main method will be 16, however, running this program reveals something different:

    Before Method: Length: 8
    Method Entry:  Length: 8
    Method Exit:   Length: 16
    After Method:  Length: 8
    

    The length of the byte array upon returning from the modifyArray method reverts to 8 instead of 16.

    Why is that?

    That's because the main method called the modifyArray method and sent a copied reference to the new byte[8] by using pass-by-value. Then, the modifyArray method threw away the copied reference by creating a new byte[16]. By the time we leave modifyArray, the reference to the new byte[16] is out of scope (and eventually will be garbage collected.) However, the main method still has reference to the new byte[8] as it only sent the copied reference and not an actual reference to the reference.

    That should demonstrate that Java will pass reference using pass-by-value.

    0 讨论(0)
  • 2020-11-30 07:26

    What are you doing in your method? If you're merely populating an existing array, then you don't need pass-by-reference semantics - either in .NET or in Java. In both cases, the reference will be passed by value - so changes to the object will be visible by the caller. That's like telling someone the address of your house and asking them to deliver something to it - no problem.

    If you really want pass-by-reference semantics, i.e. the caller will see any changes made to the parameter itself, e.g. setting it to null or a reference to a different byte array, then either method needs to return the new value, or you need to pass a reference to some sort of "holder" which contains a reference to the byte array, and which can have the (possibly changed) reference grabbed from it later.

    In other words, if your method looks likes this:

    public void doSomething(byte[] data)
    {
        for (int i=0; i < data.length; i++)
        {
            data[i] = (byte) i;
        }
    }
    

    then you're fine. If your method looks like this:

    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;
        }
    }
    

    then you need to change it to either:

    public byte[] createArray(int length)
    {
        byte[] data = new byte[length]; 
        for (int i=0; i < data.length; i++)
        {
            data[i] = (byte) i;
        }
        return data;
    }
    

    or:

    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;
        }
    }
    

    For more details, read Parameter passing in C# and Parameter passing in Java. (The former is better written than the latter, I'm afraid. One day I'll get round to doing an update.)

    0 讨论(0)
提交回复
热议问题