您可以使用关键字“ref”在.NET中执行此操作。有没有办法在Java中这样做?
答案 0 :(得分:46)
你在做什么方法?如果您只是填充现有数组,那么您不需要传递引用语义 - 无论是在.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<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;
}
}
有关详细信息,请阅读Parameter passing in C#和Parameter passing in Java。 (前者写的比后者好,我很害怕。有一天我会回来做更新。)
答案 1 :(得分:18)
实际上,在Java中,引用是按值传递。
在这种情况下,引用是byte[]
对象。任何影响对象本身的更改都将从调用方法中看到。
但是,如果您尝试替换引用,例如使用new byte[length]
,则只替换通过pass-by-value获得的引用,因此您不会更改调用方法中的引用。
以下是关于此问题的有趣读物: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
数组的长度为{然而,{1}}运行此程序会发现一些不同的东西:
16
从Before Method: Length: 8
Method Entry: Length: 8
Method Exit: Length: 16
After Method: Length: 8
方法返回时,byte
数组的长度将恢复为modifyArray
而不是8
。
为什么?
这是因为16
方法称为main
方法,并使用按值传递<将{strong>复制的引用发送到modifyArray
/ strong>即可。然后,new byte[8]
方法通过创建modifyArray
来删除复制的引用。当我们离开new byte[16]
时,对modifyArray
的引用超出范围(最终将被垃圾收集。)但是,new byte[16]
方法仍然引用{{1}因为只有发送了复制的引用,而不是对引用的实际引用。
这应该证明Java将使用pass-by-value传递引用。
答案 2 :(得分:7)
Java使用方法参数的传递值。
这篇文章可以帮到你.. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
至于OP的问题,只需将byte []数组的引用传递给方法即可。最终结果类似于通过引用传递。如果修改字节数组,调用者将能够在方法执行后看到更改。
更新以平息阻力:) =&gt;表示输出
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
}
次要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
}