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

时间:2011-03-27 04:05:34

标签: java pointers reference null setter

在我的程序中,我有两个类,一个叫做GlassPiece,另一个叫做TrackerChip。

这两个对象总是“强烈连接”,也就是说,没有两个GlassPieces可以共享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);
    }

然后一切正常。这对我来说似乎很奇怪(我所做的只是用newGlassPiece替换了LinkedGlassPiece,实例变量,参数)。但是在方法的早期,我将引用设置为彼此相等!为什么第一种方法不起作用?

P.S。我可以确认方法中没有无限循环。

4 个答案:

答案 0 :(得分:1)

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

  1. 您输入setGlassPiece,此对象的linkedGlassPiece设置为newGlassPiece的值。
  2. 然后它在oldGlassPiece上调用setTrackerChip(null)。
  3. oldGlassPiece仍然具有对原始TrackerChip的引用,因此它调用setGlassPiece(null),它将linkedGlassPiece设置为您刚刚在TrackerChip上设置的null,并且也调用new GlassPiece上的setTrackerChip(null)。
  4. 老实说,我想不出一种让你按照自己的方式工作的方法。您将不得不添加一些额外的参数,使其不再可重入。也就是说,当你在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
            }
        }
    }
    

答案 1 :(得分:0)

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

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,请查看它。

答案 2 :(得分:0)

如果总是存在一对一的关系,那么考虑将这些类合并为一个可能是值得的。

答案 3 :(得分:0)

我认为这应该有效:

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);
        }
    }
}