公司使用protobuf来作为通讯格式,一个同事这样的写法
proto文件格式:

message PlayerFightQueue {
    optional  int32      fightQueueId            = 1;
    repeated  CurArmy     curArmy                = 2;
}

使用的时候:

PlayerFightQueue.Builder fightQueue= getPlayerFightQueue();
List<CurArmy> armies = fightQueue.getCurArmyList();



这时候armies拿到的是一个java.util.Collections.unmodifiableList


要是改成这样:


PlayerFightQueue.Builder fightQueue= getPlayerFightQueue();
fightQueue.getCurArmyBuilderList();
List<CurArmy> armies = fightQueue.getCurArmyList();

这时候armies拿到的是一个RepeatedFieldBuilder.list


为什么会出现这种情况呢?
读了源码才知道protobuf是这样处理的:

  public java.util.List<com.wl.protocol.rpc.msg.CurArmyMsg.CurArmy> getCurArmyList() {
    if (curArmyBuilder_ == null) {
      return java.util.Collections.unmodifiableList(curArmy_);
    } else {
      return curArmyBuilder_.getMessageList();
    }
  }

这里发现只要curArmyBuilder_ == null才会进行包装,要不调用的是curArmyBuilder_.getMessageList()
那么curArmyBuilder_ 是什么时候变成不为null呢?
继续看代码:

 public java.util.List<com.wl.protocol.rpc.msg.CurArmyMsg.CurArmy.Builder> 
       getCurArmyBuilderList() {
    return getCurArmyFieldBuilder().getBuilderList();
  }
  private com.google.protobuf.RepeatedFieldBuilder<
      com.wl.protocol.rpc.msg.CurArmyMsg.CurArmy, com.wl.protocol.rpc.msg.CurArmyMsg.CurArmy.Builder, com.wl.protocol.rpc.msg.CurArmyMsg.CurArmyOrBuilder> 
      getCurArmyFieldBuilder() {
    if (curArmyBuilder_ == null) {
      curArmyBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
          com.wl.protocol.rpc.msg.CurArmyMsg.CurArmy, com.wl.protocol.rpc.msg.CurArmyMsg.CurArmy.Builder, com.wl.protocol.rpc.msg.CurArmyMsg.CurArmyOrBuilder>(
              curArmy_,
              ((bitField0_ & 0x00000080) == 0x00000080),
              getParentForChildren(),
              isClean());
      curArmy_ = null;
    }
    return curArmyBuilder_;
  }

发现只要是调用了builder方法会改变curArmyBuilder_ 而curArmy_就会被变成null

遇到这种情况还是不要偷懒,老老实实的深复制吧,也许就会出现埋点很深的坑


nohup
160 声望9 粉丝