当前位置:  开发笔记 > 编程语言 > 正文

Java:如何通过引用传递byte []?

如何解决《Java:如何通过引用传递byte[]?》经验,为你挑选了3个好方法。

您可以使用关键字"ref"在.NET中执行此操作.有没有办法在Java中这样做?



1> Jon Skeet..:

你在用你的方法做什么?如果您只是填充现有数组,那么您不需要传递引用语义 - 无论是在.NET中还是在Java中.在这两种情况下,引用都将按值传递 - 因此调用者可以看到对象的更改.这就像告诉别人你的房子的地址,并要求他们提供一些东西 - 没问题.

如果你真的想要传递引用语义,即调用者将看到对参数本身所做的任何更改,例如将其设置为null或引用不同的字节数组,那么任何一种方法都需要返回新值,或者你需要将引用传递给某种"holder",其中包含对字节数组的引用,并且可以在以后从中获取(可能已更改)引用.

换句话说,如果您的方法看起来像这样:

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
{
    public T value; // Use a property in real code!
}

public void createArray(Holder holder, int length)
{
    holder.value = new byte[length]; 
    for (int i=0; i < length; i++)
    {
        holder.value[i] = (byte) i;
    }
}

有关更多详细信息,请参阅参数传递C#和参数传递Java.(前者写的比后者好,我很害怕.有一天我会回来做更新.)



2> coobird..:

实际上,在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长度数组,该数组将调用该方法,在该方法中创建一个新的长度数组.8mainmodifyArraybyte16

可能看起来通过bytemodifyArray方法中创建一个新数组,byte返回到该main方法时数组的长度将是16,但是,运行此程序会发现一些不同的东西:

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

bytemodifyArray方法返回时数组的长度恢复为8而不是16.

这是为什么?

那是因为该main方法调用了modifyArray方法并通过使用pass-by-value 将复制的引用new byte[8]发送给该方法.然后,该方法通过创建a抛弃复制的引用.到我们离开时,对该引用的引用超出了范围(并最终将被垃圾收集.)但是,该方法仍然引用了它,因为它只发送了复制的引用而不是对引用的实际引用.modifyArraynew byte[16]modifyArraynew byte[16]mainnew byte[8]

这应该表明Java将使用pass-by-value传递引用.



3> Gishu..:

Java对方法参数使用pass by值.

Primitives(int,boolean等)是Java中的特殊情况..本身不是对象.在这种情况下,将原语(参数)的副本传递给函数.这与通过价值理论很好地吻合.

对于对象,会发生的是对象的引用是按值传递的(引用的副本而不是对象)...但两个引用都指向同一个对象.因此,如果修改方法中的对象参数,则将修改实际对象.

这篇文章应该可以帮到你.. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

至于OP的问题,只需将byte []数组的引用传递给方法.最终结果类似于通过引用传递.如果修改字节数组,调用者将能够在方法执行后看到更改.

更新以平息阻力:) =>表示输出

.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

次要mods reqd:使用hashCode()和+来连接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  
}

推荐阅读
手机用户2402851335
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有