キーワード「ref」を使用して、.NETでそれを行うことができます。Javaでそうする方法はありますか?
3 に答える
あなたはあなたの方法で何をしていますか?既存の配列にデータを入力するだけの場合は、.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でのパラメーターの受け渡し」を参照してください。(前者は後者よりもよく書かれているので、恐れています。いつか更新を行うことになります。)
実際、Java では、参照は値渡しです。
この場合、参照はbyte[]
オブジェクトです。オブジェクト自体に影響を与える変更は、呼び出し元のメソッドから確認できます。
ただし、たとえば を使用して参照を置き換えようとすると、 new byte[length]
値渡しで取得した参照のみが置き換えられるため、呼び出し元メソッドの参照は変更されません。
この問題について興味深い記事があります: Java は Pass-by-Value だめ!
具体的な例を次に示します。
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
何故ですか?
これは、main
メソッドがメソッドを呼び出し、コピーされた参照をpass-by-valueを使用して にmodifyArray
送信したためです。次に、メソッドは. を終了するまでに、 への参照は範囲外です (最終的にはガベージ コレクションが実行されます)。しかし、メソッドは、参照への実際の参照ではなく、コピーされた参照を送信しただけなので、まだ への参照を保持しています。new byte[8]
modifyArray
new byte[16]
modifyArray
new byte[16]
main
new byte[8]
これは、Java が値渡しを使用して参照を渡すことを示しているはずです。
Javaは、メソッド引数に値渡しを使用します。
- プリミティブ(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
}
ジャワランド
Minor 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
}