提问人:Mahendra 提问时间:12/2/2008 最后编辑:Mahendra 更新时间:11/16/2016 访问量:55930
Java:如何通过引用传递 byte[]?
Java: How to pass byte[] by reference?
答:
Java 对方法参数使用传递 by 值。
- 原语(int、boolean 等)是 Java 中的特例。不是对象本身。在这种情况下,将基元(参数)的副本传递到函数中。这与价值传递理论相吻合。
- 对于对象,发生的情况是对象的引用按值传递(创建引用的副本而不是对象)...但两个引用都指向同一个对象。因此,如果在方法中修改对象参数,则实际对象将被修改。
这篇文章应该对你有所帮助。http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
至于 OP 的问题,只需将对 byte[] 数组的引用传递给方法即可。最终结果类似于通过引用传递。如果修改字节数组,调用方将能够看到方法执行后的更改。
更新以平息电阻 :) => 表示输出
.NET 土地
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
}
爪哇土地
次要修改 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
}
评论
实际上,在 Java 中,引用是按值传递的。
在本例中,引用是一个对象。任何影响对象本身的更改都将从调用方方法中看到。byte[]
但是,如果尝试替换引用(例如,使用 ),则只会替换通过按值传递获取的引用,因此不会更改调用方方法中的引用。new byte[length]
这里有一个关于这个问题的有趣读物:Java is Pass-by-Value 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
为什么?
这是因为该方法调用了该方法,并使用 pass-by-value 发送了对新 byte[8]
的复制引用。然后,该方法通过创建一个新 byte[16]
来丢弃复制的引用。当我们离开时,对 的引用已经超出了范围(最终将被垃圾回收)。但是,该方法仍然引用了 ,因为它只发送了复制的引用,而不是对引用的实际引用。main
modifyArray
modifyArray
modifyArray
new byte[16]
main
new byte[8]
这应该表明 Java 将使用 pass-by-value 传递引用。
你的方法在做什么?如果只是填充现有数组,则不需要按引用传递语义 - 无论是在 .NET 中还是在 Java 中。在这两种情况下,引用都将按值传递 - 因此调用方将看到对对象的更改。这就像告诉别人你家的地址,然后让他们把东西送到那里——没问题。
如果你真的想要按引用传递的语义,即调用者将看到对参数本身所做的任何更改,例如将其设置为 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 中的参数传递。(恐怕前者比后者写得好。总有一天我会开始做一个更新。
评论