尝试强连接对象时出现奇怪的指针问题
在我的程序中,我有两个类,一类称为 GlassPiece,一类称为 TrackerChip。
这两个对象始终是“强连接”的,即没有两个GlassPiece可以共享一个TrackerChip,也没有两个TrackerChip可以共享一个GlassPiece。因此,在我的 setter 方法中,我需要小心地断开任何旧引用的连接,如下所示:
public class TrackerChip
{
GlassPiece linkedGlassPiece;
public void setGlassPiece(GlassPiece newGlassPiece)
{
GlassPiece oldGlassPiece = linkedGlassPiece;
linkedGlassPiece = newGlassPiece;
if(oldGlassPiece != null)
{
oldGlassPiece.setTrackerChip(null); //disconnect old GlassPiece
}
if(linkedGlassPiece != null && linkedGlassPiece.getTrackerChip() != this)
{
linkedGlassPiece.setTrackerChip(this); //update counterpart
}
}
}
并且方法 GlassPiece.setTrackerChip(TrackerChip) 的工作方式完全相同。
问题是,上面的代码实际上不起作用,并且当尝试管理几个不同的 GlassPieces 和 TrackerChips 之间的链接时会发生奇怪的事情。但是,如果我将最后一部分替换为:
if(newGlassPiece != null && newGlassPiece.getTrackerChip() != this)
{
newGlassPiece.setTrackerChip(this);
}
那么一切都会正常工作。这对我来说似乎很奇怪(我所做的只是将实例变量 linkedGlassPiece 替换为参数 newGlassPiece)。但在该方法的早期,我将引用设置为彼此相等!为什么第一种方法不起作用?
PS我可以确认该方法中没有无限循环。
In my program I have two classes, one called GlassPiece, and one called TrackerChip.
These two objects are always "strongly connected", that is, no two GlassPieces can share a TrackerChip, and no two TrackerChips can share a GlassPiece. Therefore in my setter methods, I need to take care to disconnect any old references hanging around, as so:
public class TrackerChip
{
GlassPiece linkedGlassPiece;
public void setGlassPiece(GlassPiece newGlassPiece)
{
GlassPiece oldGlassPiece = linkedGlassPiece;
linkedGlassPiece = newGlassPiece;
if(oldGlassPiece != null)
{
oldGlassPiece.setTrackerChip(null); //disconnect old GlassPiece
}
if(linkedGlassPiece != null && linkedGlassPiece.getTrackerChip() != this)
{
linkedGlassPiece.setTrackerChip(this); //update counterpart
}
}
}
and the method GlassPiece.setTrackerChip(TrackerChip) works exaxctly the same way.
The thing is, the above code doesn't actually work, and strange stuff happens when trying to manage linking between several different GlassPieces and TrackerChips. However, if I replace the last part with:
if(newGlassPiece != null && newGlassPiece.getTrackerChip() != this)
{
newGlassPiece.setTrackerChip(this);
}
Then everything works properly. This seems very strange to me (all I did was replaced linkedGlassPiece, the instance variable, with newGlassPiece, the parameter). But early in the method I set the references equal to each other! Why does the first method not work?
P.S. I can confirm there is no infinite loop in the method.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
至于为什么这不起作用,你是对的,它不会陷入无限循环,但它不会做你期望的事情。
老实说,我想不出一种方法让它按照你的方式工作。您必须添加一些额外的参数,使其不再可重入。也就是说,当您在 oldGlassPiece 上调用 setTrackerChip 时,它不会转身调用相同的 TrackerChip 将其引用设置为 null。也许只是一个布尔标志,表明它不应该使第二级引用无效。
这是一些代码:
As for why this isn't working, you're right, it won't hit an endless loop, but it's not going to do what you expect.
I honestly can't think of a way to get it to work the way you're going. You would have to add some additional parameters such that it would no longer be re-entrant. Namely, when you call setTrackerChip on the oldGlassPiece, it's not going to turn around and call the same TrackerChip back setting its reference to null. Perhaps just a boolean flag that would indicate that it should not null out the second level references.
Here's some code:
我建议不要采用这种方法,而只使用一对静态 HashMap 来管理关系。那可能会简单得多。如果您的用例不是单线程,则可能存在线程安全问题,但您只需要同步设置它的方法。也许创建一个关系管理对象如下:
实际上,在 Google Guava 库中,甚至有一个类可以用于此类事情,名为 BiMap,查看一下。
Instead of taking this approach, I would recommend just having a pair of static HashMaps that manage the relationships. That would probably be far simpler. There could be thread safety issues if your use case is not single threaded, but you'd just need to synchronize the method that sets it up. Maybe create a relationship management object as follows:
Actually, in the Google Guava library, there is even a class ready to use for this sort of thing called BiMap, check it out.
如果始终存在一对一的关系,则可能值得考虑将这些类合并为一个。
If there is always a one to one relationship, it might be worthwhile to consider merging those classes into one.
我认为这应该有效:
This should work I think: