尝试强连接对象时出现奇怪的指针问题

发布于 2024-10-27 08:59:30 字数 1215 浏览 1 评论 0原文

在我的程序中,我有两个类,一类称为 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秋凉 2024-11-03 08:59:30

至于为什么这不起作用,你是对的,它不会陷入无限循环,但它不会做你期望的事情。

  1. 您输入setGlassPiece,将此对象的linkedGlassPiece 设置为newGlassPiece 的值。
  2. 然后它在 oldGlassPiece 上调用 setTrackerChip(null)。
  3. oldGlassPiece 仍然具有对原始 TrackerChip 的引用,因此它调用 setGlassPiece(null),它将 linkedGlassPiece 设置为您刚刚在 TrackerChip 上设置的 null,并在 NEW GlassPiece 上调用 setTrackerChip(null)。

老实说,我想不出一种方法让它按照你的方式工作。您必须添加一些额外的参数,使其不再可重入。也就是说,当您在 oldGlassPiece 上调用 setTrackerChip 时,它不会转身调用相同的 TrackerChip 将其引用设置为 null。也许只是一个布尔标志,表明它不应该使第二级引用无效。

这是一些代码:

public class TrackerChip
{
    GlassPiece linkedGlassPiece;

    public void setGlassPiece(GlassPiece newGlassPiece)
    {
         setGlassPiece(newGlassPiece, true);
    }

    public void setGlassPiece(GlassPiece newGlassPiece, boolean reentrant)
    {
        GlassPiece oldGlassPiece = linkedGlassPiece;

        linkedGlassPiece = newGlassPiece;

        if(reentrant && oldGlassPiece != null)
        {
            oldGlassPiece.setTrackerChip(null, false); //disconnect old GlassPiece
        }

        if(linkedGlassPiece != null && linkedGlassPiece.getTrackerChip() != this)
        {
            linkedGlassPiece.setTrackerChip(this); //update counterpart
        }
    }
}

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.

  1. You enter setGlassPiece, linkedGlassPiece for this object is set to the value of newGlassPiece.
  2. Then it calls setTrackerChip(null) on the oldGlassPiece.
  3. The oldGlassPiece still has a reference to the original TrackerChip, so it calls setGlassPiece(null), which sets linkedGlassPiece to null that you just set on the TrackerChip, and calls setTrackerChip(null) on the NEW GlassPiece as well.

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:

public class TrackerChip
{
    GlassPiece linkedGlassPiece;

    public void setGlassPiece(GlassPiece newGlassPiece)
    {
         setGlassPiece(newGlassPiece, true);
    }

    public void setGlassPiece(GlassPiece newGlassPiece, boolean reentrant)
    {
        GlassPiece oldGlassPiece = linkedGlassPiece;

        linkedGlassPiece = newGlassPiece;

        if(reentrant && oldGlassPiece != null)
        {
            oldGlassPiece.setTrackerChip(null, false); //disconnect old GlassPiece
        }

        if(linkedGlassPiece != null && linkedGlassPiece.getTrackerChip() != this)
        {
            linkedGlassPiece.setTrackerChip(this); //update counterpart
        }
    }
}
美羊羊 2024-11-03 08:59:30

我建议不要采用这种方法,而只使用一对静态 HashMap 来管理关系。那可能会简单得多。如果您的用例不是单线程,则可能存在线程安全问题,但您只需要同步设置它的方法。也许创建一个关系管理对象如下:

public class RelationshipMgr {
  HashMap<GlassPiece, TrackerChip> gpMap;
  HashMap<TrackerChip, GlassPiece> tcMap;

  public void setRelationship(GlassPiece gp, TrackerChip tc) {
    gpMap.put(gp, tc);
    tcMap.put(tc, gp);
  }
}

实际上,在 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:

public class RelationshipMgr {
  HashMap<GlassPiece, TrackerChip> gpMap;
  HashMap<TrackerChip, GlassPiece> tcMap;

  public void setRelationship(GlassPiece gp, TrackerChip tc) {
    gpMap.put(gp, tc);
    tcMap.put(tc, gp);
  }
}

Actually, in the Google Guava library, there is even a class ready to use for this sort of thing called BiMap, check it out.

苹果你个爱泡泡 2024-11-03 08:59:30

如果始终存在一对一的关系,则可能值得考虑将这些类合并为一个。

If there is always a one to one relationship, it might be worthwhile to consider merging those classes into one.

帅的被狗咬 2024-11-03 08:59:30

我认为这应该有效:

public class TrackerChip {
    GlassPiece linkedGlassPiece;

    public void setGlassPiece(GlassPiece newGlassPiece) {
        if (linkedGlassPiece == newGlassPiece) {
            return;
        }
        if (linkedGlassPiece != null) {
            GlassPiece tmp = linkedGlassPiece;
            linkedGlassPiece = null;
            tmp.setTrackerChip(null);
        }
        if (newGlassPiece != null) {
            linkedGlassPiece = newGlassPiece;
            linkedGlassPiece.setTrackerChip(this);
        }
    }
}

This should work I think:

public class TrackerChip {
    GlassPiece linkedGlassPiece;

    public void setGlassPiece(GlassPiece newGlassPiece) {
        if (linkedGlassPiece == newGlassPiece) {
            return;
        }
        if (linkedGlassPiece != null) {
            GlassPiece tmp = linkedGlassPiece;
            linkedGlassPiece = null;
            tmp.setTrackerChip(null);
        }
        if (newGlassPiece != null) {
            linkedGlassPiece = newGlassPiece;
            linkedGlassPiece.setTrackerChip(this);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文