web-dev-qa-db-ja.com

Java:参照でbyte []を渡す方法は?

.NETでは、キーワード "ref"を使用してそれを行うことができます。 Javaでそうする方法はありますか?

21
Mahendra

あなたの方法で何をしていますか?既存の配列にデータを入力するだけの場合は、.NETでもJavaでも、参照渡しのセマンティクスは必要ありません。どちらの場合も、参照は値で渡されます。したがって、objectへの変更は、呼び出し元に表示されます。それは誰かにあなたの家の住所を伝え、それに何かを届けるように頼むようなものです-問題ありません。

あなたが本当に参照渡しのセマンティクスが必要な場合、つまり、呼び出し元はパラメータ自体に加えられた変更をすべて見ることができます。 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で渡されるパラメーター を参照してください。 (前者の方が後者よりも優れていると思います。恐れます。いつかアップデートに取り掛かります。)

46
Jon Skeet

実際、Javaでは、参照は値で渡されますです。

この場合、参照は_byte[]_オブジェクトです。オブジェクト自体に影響する変更は、呼び出し元のメソッドから確認されます。

ただし、たとえば_new byte[length]_を使用して参照を置き換えようとすると、値渡しによって取得された参照のみが置き換えられるため、呼び出し元メソッドの参照は変更されません。

この問題についての興味深い記事は次のとおりです。 Javaは値渡しのダンミです


具体的な例を次に示します。

_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メソッドがmodifyArrayメソッドを呼び出して_new byte[8]_へのコピーされた参照をpass-by-valueを使用して送信したためです。次に、modifyArrayメソッド_new byte[16]_を作成して、コピーされた参照を破棄しました。 modifyArrayを終了するときまでに、_new byte[16]_への参照は範囲外です(最終的にはガベージコレクションされます。)ただし、mainメソッドは、_new byte[8]_への参照をまだ持っていますコピーされた参照を送信であり、参照への実際の参照ではありません。

これは、Javaが値渡しを使用して参照を渡すことを示しています。

18
coobird

Javaはメソッド引数に値渡しを使用します

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

ジャワランド

マイナー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  
}
7
Gishu