我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=wotgdo5wqshi
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=wotgdo5wqshi
本篇文章没有什么干货,仅是我的一次调试经历。
昨天在调试FIDO项目,运行时发现某个变量的值和我设置的不对。调试进去,几番折腾,吓呆了我:
仅仅经过一个赋值,就把赋值和被赋值的变量都改变了?我的所有知识都无法解释这个问题。
没办法,现实摆在眼前。只能通过一系列的实验排除问题。
我在赋值前进行clone(),入参不再改变。根据1和2,我觉得应该是该对象的变量出的问题。
我不再进行入参的赋值,而是在构造器直接赋值this.attestationType = new short[1]; this.attestationType[0] = 1;
。结果:第一句赋值成功,第二句没有效果。
我不再在构造函数中赋值,而是另开一个方法单独赋值。问题依然存在。
我开始怀疑是不是注解的问题。@TagMember
是一个RUNTIME注解,功能类似GSON,用于进行对象和特定数据格式(TLV)之间的转换。我把注解注释掉,问题不再复现!
我怀疑是注解里面的变量有问题。于是我把supportedExtensionIDs
的注解复制到attestationType
上。问题依然不再复现。
这就奇怪了,为什么注解里的值会影响变量本身呢?这和注解的原理和功能并不一致。为了防止“改动完又改回去,突然就可以了”这样的怪圈,我回归了一下原代码,问题重新出现。
接下来更奇怪的事情出现了。我把supportedExtensionIDs
的值从null改回到{"1", "2"}
,问题不再出现!这个问题我在步骤1就已经测试过了,这是真的出现了“改动完又改回去,突然就可以了”的致命事件。。我被打懵了。。
我再改回null,问题又回来了。
我试着精简我的问题模型。我把其他变量都删掉了,只留下attestationType
。问题依然存在。
继续关注刚刚注释注解的线索。我的其他变量都有注解,却偏偏只有这个变量出现了问题。由于步骤7的现象,我把attestationType
和supportedExtensionIDs
的位置交换,并把注解的值也交换了。问题依然存在。
我把attestationType
的类型修改为byte[]和int[]。赋值问题不再出现!于是我现在得到的结论是:被注解的short[]类型会出现赋值问题。
为什么偏偏是short[]类型呢?我想的有点偏,我认为是注解的short tag()这个方法导致的问题。但修改TagMember这个tag又会影响太多代码,于是我拷贝了@TagMember类,并定义为@TagMember2。将attestationType的注解改为@TagMember2,并改为int tag()。问题消失了。我自豪的猜想:难道我遇到了JAVA编译器的问题?
就都麻袋,还不能太早下结论。我把@TagMember2改回short tag()。现在两个注解除了类名都一样了。运行,没有赋值问题。意思就是:和short tag()没有关系。
一样的注解,但是却不一样的结果?只有@TagMember才会出现问题,@TagMember2没有问题,但他们明明是一样的。@TagMember到底有什么特别之处呢?
哦,我想起来了。我在父类里面会对其进行反射调用,取值构造新数据结构(步骤4有提到)。而这个方法会通过toString()执行。
caocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocaocao!!!!!!!!!!!一下子都想通了。
验证一下,我把父类的继承去掉,让该类继承Object。赋值问题消失。
我检查了一下toString()中我对short[]类型的处理,发现我在赋值的时候仅做了浅拷贝(也就是直接赋值),然后做了修改值的操作。而在debug过程中每一个单步调试IDE都会调用对象的toString()方法,而toString()方法会修改short[]类型的变量,所以出现了一开始的赋值问题。
关于步骤7里面的线索(supportedExtensionIDs
会影响attestationType
的赋值成功):是因为我的toString()方法里没有对String[]类型的处理分支。而在null的时候,我的处理会忽略这个变量,则流程继续走下去,把short[]的处理分支执行了。而在非null的时候,因为toString()无法处理,会直接报错,则没有走到处理short[]的分支。所以supportedExtensionIDs
在非null的时候,attestationType
的赋值不受影响。
关于步骤7和步骤1的同样环境不同结果的问题:最后我无法复现步骤1的情况,恐怕是调试期间我不小心改了哪里吧。。我认为不会是很值得研究的原因,解决了主要疑惑和次要疑惑,有时候该放手就放手吧。
我在整理文章的时候想通了步骤21的疑惑。是断点位置的问题。在后面的调试中,我把断点设在了构造函数末尾,则supportedExtensionIDs
的值会影响到attestationType
(因为在那个时候IDE才开始调用toString())。而如果是一步一步调试,则supportedExtensionIDs
被赋值前attestationType
已经被修改了。
步骤6的问题,是因为我刚好把步骤22所说的断电给移动了,导致了这个现象,其实和值并没有关系。
版权所有,转载请注明出处:
http://sickworm.com/?p=184