AndroidでNFC-Fのコマンド送受信をするときは、NfcF.transceive()を使う。
こんなメソッドだ。
public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true);
}
戻ってくるのは、応答した結果のbyte[]。
さて、このbyte[]、どうしたらいいんだろうか?
どっちかだと思う。
- transceive()以下でメモリ確保してあげてるから、そのまま使っていいよ。
- 暫定でメモリを渡してるんだから、さっさと自分でコピーしてね。
悩んでいたが、文字にしてみると、前者だろう、ということに気付いた。
まだ言語仕様がよくわかっていないが、Javaの引数はCの引数と同じイメージでいいようだ。
void f() {
byte[] a = new byte[] { 1, 2, 3 }; //「new byte[]」はいらない?
g(a);
h(a);
}
void g(byte[] a) {
a[0] = 4;
}
void h(byte[] b) {
b = new byte[] { 5, 6, 7 };
}
f()が持つa[]は、g()によって書き換えはされるが、h()によって置き換えられることはない。
だから、相手先にメモリを確保してもらうなら、戻り値でもらうようにするのがよさそうだ。
引数で返してもらうなら、配列にしてしまうしかないのかな?
void f() {
byte[][] a = new byte[1][];
a[0] = new byte[] { 1, 2, 3 };
h(a);
}
void h(byte[][] b) {
b[0] = new byte[] { 5, 6, 7 };
}
なんか、C#の文法とかが入り交じってしまって、コンパイルもしてないから、私が思っているイメージが伝わればいいかな、ということで。
そしてまだよくわかってないものに、System.arraycopy()が挙げられる。
System.arraycopy()は、シャローコピー(shallow copy)だそうだ。
って、みんないってるけど、言語仕様なんだろうか?
package test;
public class Test {
public static void main(String[] args) {
byte[] a = { 1, 2, 3, 4, 5 };
byte[] b = { 6, 7, 8, 9, 0 };
byte[] c = new byte[2];
System.arraycopy(a, 0, c, 0, 1);
System.arraycopy(b, 0, c, 1, 1);
//最初の値
System.out.print("a:");
for(byte k : a) {
System.out.print(k + " ");
}
System.out.println();
System.out.print("b:");
for(byte k : b) {
System.out.print(k + " ");
}
System.out.println();
System.out.print("c:");
for(byte k : c) {
System.out.print(k + " ");
}
System.out.println();
//書き換え
c[0] = 10;
c[1] = 11;
//最後の値
System.out.println("----------");
System.out.print("a:");
for(byte k : a) {
System.out.print(k + " ");
}
System.out.println();
System.out.print("b:");
for(byte k : b) {
System.out.print(k + " ");
}
System.out.println();
System.out.print("c:");
for(byte k : c) {
System.out.print(k + " ");
}
System.out.println();
}
}
結果
a:1 2 3 4 5
b:6 7 8 9 0
c:1 6
----------
a:1 2 3 4 5
b:6 7 8 9 0
c:10 11
あれ?
参照してるんだから、参照先が変わると参照元も変わるんじゃないの??
じゃあ、参照元だけ変更して、参照先はそのままにしてみた。
結果
a:1 2 3 4 5
b:6 7 8 9 0
c:1 6
----------
a:10 2 3 4 5
b:11 7 8 9 0
c:1 6
変わらん・・・。
ちゃんと値コピーされている。
いや、不思議に思ったのだ。
コピーって配列の一部だけコピーすることができるけど、それをわざわざ「ここからここまではこのオブジェクトを参照」「ここからここまでは、あのオブジェクト参照」なんて管理するのは、非常に面倒だし、かえって遅くなるではないか。
System.arraycopy()の「shallow」な対象は、配列オブジェクトではなく、配列オブジェクトの要素部分ということなんだな。
上の例では、要素部分はプリミティブなbyte型だから、そのまま値コピーされている。
要素部分がStringみたいな型だったら、それはアドレスをコピーするだけにしていて、その先は同じものを参照しますよ、ということか。
要素部分がオブジェクト型の場合は、アドレスだけをコピー
要素部分がプリミティブ型の場合は、アドレスに相当するのが値なので、値コピー
試してよかった・・・。
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。