今天在使用java写代码的时候,用byte数组作为map的key来使用,发现在遍历的时候get到之前传进去的值总是为空,很是困惑,后来查了下资料发现java中的字节数组不能直接作为map的key来使用.
/**
* 找到当前区块链中所有UTXO
*/
public List findAllUtxos(String sendAddress) {
//遍历所有的区块,找出交易发起人能够解锁的所有没有花费的交易输出
List utxoInfos = new ArrayList<>();
Iterator blockIterator = new Iterator(tailHash);
//byte[]不能直接作为map的key使用,所以需要将txid转换成string才能使用
Map> spentOutputs = new HashMap<>();
for (; ; ) {
Block block = blockIterator.getBlock();
for (Transaction tx : block.transactions) {
System.out.println("tag2:outputs length is " + tx.outputs.length + " tx id is " + new BigInteger(tx.id).toString(16));
ScanTransaction:
//遍历所有的交易输出
for (int i = 0; i < tx.outputs.length; i++) {
//如果发现该交易已经有被引用的交易输出,就开始判断
List idList = spentOutputs.get(new String(tx.id));
if (idList != null) {
System.out.println(idList.toString());
for (Integer index : idList) {
if (i == index) {
System.out.println("find spent output,continue scan next input");
continue ScanTransaction;
}
}
}
//如果交易发起人能使用,将其添加进去
TxOutput output = tx.outputs[i];
if (output.canUnlockUTXOWith(sendAddress)) {
UtxoInfo utxoInfo = new UtxoInfo();
utxoInfo.id = tx.id;
utxoInfo.index = i;
utxoInfo.output = output;
utxoInfos.add(utxoInfo);
}
}
//遍历所有的交易输入,找到已经花费掉的,每次循环都创建一个List对象
List spentTxIds = new ArrayList<>();
if (!tx.isCoinBase()) {
for (int i = 0; i < tx.inputs.length; i++) {
TxInput input = tx.inputs[i];
if (input.canUnlockWith(sendAddress)) {
spentTxIds.add(i);
//一定要注意这里的txid是输入中引用的交易id,不是本次循环的txid
System.out.println("find used utxo,tx id is " + new BigInteger(input.txId).toString(16) + "index is " + i);
spentOutputs.put(new String(input.txId), spentTxIds);
}
}
}
}
if (block.prevHash == null || block.prevHash.length == 0) {
break;
}
}
return utxoInfos;
}
原因是这样的,当使用byte[]作为key的时候,map会对这个字节数组的地址进行hashcode得到一个值作为key,而不是以内容作为它的key,所以两次byte数组地址不一样的话,得到的结果就会完全不同.
有三种解决方案:
Wrapping in a String, but then you have to be careful about encoding issues (you need to make certain that the byte -> String -> byte gives you the same bytes).
Use List(can be expensive in memory).
Do your own wrapping class, writing hashCode and equals to use the contents of the byte array.
分别是将byte转成字符串String,我在代码里也是这么改的;第二是使用List代替;第三是实现你自己的包装类,重写hashcode和equals方法来达到以内容作为key的目的.
再来类比一下go语言中的map,map的key需要能够进行比较的数据类型.那些内置复杂类型如slice,function和map以及包含这些类型字段的结构体也是不能用来做map的key的.
参考资料:
--EOF--
发表于 2018-12-01 15:25:00
,并被添加「java、go」标签。
本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。更多说明 »
提醒:本文最后更新于 830 天前,文中所描述的信息可能已发生改变,请谨慎使用。
专题「java相关」的其它文章 »