【问题标题】:<Lists> emptying themselves<Lists> 清空自己
【发布时间】:2011-05-17 00:37:57
【问题描述】:

晚上好,

我尝试在 Java 上实现的方法有一个奇怪的问题。 我会尽量描述它:

基本上,它所做的是检查 Epsilon-Non Deterministic State Machine 将达到的下一个状态,给定一个状态和一系列可能的转换。 “loadEpsilon(List)”方法为给定的状态列表加载可能的 epsilon 转换。

      if (transitionList.isEmpty()){
          return new HashSet<State>(stateEntryList);
      }
      else{
          for (int i=0; i <= transitionList.size()-1; i++){
              for (int j=0; j <= stateEntryList.size()-1; j++){
                  for (Transition tr : this.transitions()){ 
                      if ((tr.fromState() == stateEntryList.get(j)) && (tr.label() == transitionList.get(i))){
                          if (!stateExitList.contains(tr.toState())){
                              stateExitList.add(tr.toState());
                          }
                      }
                  }
              }
              stateEntryList.clear();
              stateEntryList = loadEpsilon(stateExitList);
              stateExitList.clear();
          }
          return new HashSet<State>(stateEntryList);
              }

所以,用跟踪“System.out.print”来填充整个代码,直到

    stateExitList.clear();

一切正常。但是,经过该行,我在该句子之后打印两个列表(StateExitList 和 StateEntryList),它们都已消失。

我只是想不通他们为什么要清空自己。

有没有帮助的机会?

非常感谢。

编辑:这将是 loadEpsilon 的代码:

  public List<State> loadEpsilon(List<State> states) throws NoInitialStateException{
      State stateRead;
      if (states.isEmpty()){ 
          if (this.getInitialState() == null){
              throw new NoInitialStateException();
          }
          states.add(this.getInitialState());
          return loadEpsilon(states);
      }
      else{
          for (int i=0; i <= states.size()-1;i++){
              stateRead = states.get(i);
              for (Transition tr : this.transitions()){
                  if ((tr.fromState() == stateRead) && (tr.label().isEpsilon()) && (!states.contains(tr.toState()))){
                      states.add(tr.toState()); 
                      System.out.print(states.size());
                  }
              }
          }
      }
      return states; 
  } 

列表的声明如下:

      List<State> stateEntryList = new ArrayList<State>();
      stateEntryList = loadEpsilon(stateEntryList);       
      List<State> stateExitList = new ArrayList<State>();
      List<Label> listaLabels = new ArrayList<Label>();
      listaLabels.addAll(Arrays.asList(labels));

【问题讨论】:

  • 在我看来,您在两个列表上都调用了clear(),这将清空两个列表。您的问题是“为什么两个列表都是空的”?要么我很困惑,要么你很困惑。
  • 您正在清除 stateEntryList 和 stateExitList N 次(每个 transitionList 项目一次)。我不确定这是否是您想要的。
  • @Travis Webb:不,我使用 clear() 精确地清空了两个列表。
  • @Mohamed Nuur:我正在清除列表 N 次,以便它在内部循环中使用的列表为空。但是,我希望在 transitionList 中的最后一个元素之后,列表不会自己清空。

标签: java list for-loop


【解决方案1】:

如果在您调用loadEpsilon 之后调用stateExitList.clear() 之后stateEntryList 为空,则表明List 指向loadEpsilon 返回的loadEpsilon 以某种方式与传递给它的stateExitList 相关联。也许loadEpsilon 返回的列表正在使用传递给它的列表作为后备存储或类似的东西?您确实需要将代码发布到loadEpsilon


已编辑:

嗯,这就解释了。您的 loadEpsilon 正在返回传递给它的 List。它返回的对象与给出的对象完全相同。因此,您最终会得到两个名称引用的同一个对象。但是因为它下面是同一个物体,所以当你清除它时,它就被清除了。

你基本上是这样做的:

List<String> list1 = new ArrayList<String>();
list1.add("foo");
list1.add("bar");

List<String> sameList = list1;
sameList.add("quux");

list1.clear();

这是否更清楚为什么清除一个列表会清除它们“两者”? (同样,只有一个对象被两个引用变量引用)。

【讨论】:

  • 我刚刚编辑了包含loadEpsilon()代码的代码。
  • 非常感谢!我确实在每个代码行之间塞了一个print,以查看东西在哪里清空我的列表,但没有意识到它可能是这样的:)
  • 是的,是的。这就很清楚了。我想我不会使用=,而是使用addAll() 方法来避免这种行为。再次感谢:)
  • 编辑:在测试了 addAll() 之后,我可以肯定地说它就像一个魅力。
【解决方案2】:

列表在 Java 中不会自发地清空自己。相信我。它不会发生。

这意味着必须有不同的解释:

  • 也许这两个列表实际上是同一个对象,或者是同一个对象上的视图。所以清除一个列表会清除第二个。

  • 也许 clear 在其他地方的第二个列表中被调用,而您没有发现它。或者它可能是由于 remove / removeAll 调用而发生的。

  • 可能第二个列表已经为空。例如,您认为要添加到第二个列表的地方实际上是添加到完全不同的列表对象中。

  • 也许您使用的自定义列表实现有错误行为;例如其他一些操作实际上是作为错误的副作用删除内容。

  • 也许是别的东西……

如果没有所有相关代码(包括跟踪打印代码)和跟踪打印的输出,我们不会为您提供帮助。

【讨论】:

  • 哦,我花了一些时间来清除所有的痕迹,以为这只会让你们在这里混乱:(
  • 非常感谢您的宝贵时间。下次我会尝试以更详细的方式发布问题。
【解决方案3】:

loadEpsilon 是否使用延迟执行?这可以解释为什么清空传递给它的列表会导致它返回的列表为空。

【讨论】:

  • 很抱歉,延期执行是什么意思?但是,在 loadEpsilon 之后和最后一个 stateExitList.clear() 之前打印列表时,它们都按应有的方式显示(包含正确的元素)。只有当我清除 stateExitList 时,它们才会消失。
  • “延迟执行”意味着一个方法在被调用时不做它的工作。相反,它可能会创建一个在未来任意时间执行该工作的线程。因此,如果您在实际工作完成之前清除了列表,则可能会出现问题。但是,鉴于您所说的,这听起来不像是在使用延迟执行。
  • 我不确定 Java,但在 C# 中,您可以使用迭代器块在给定输入序列的情况下返回不同的序列。在您的代码开始迭代输出序列之前,迭代器块不会迭代输入序列。通过这种方式,您可以设置一个转换,然后清除输入列表,当您迭代您认为是输出列表的内容时,那里什么都没有,因为转换中使用的迭代器块没有任何东西可以迭代了。
  • 谢谢你们的解释,显然不是延迟执行,但至少我得知道它是什么:)
猜你喜欢
  • 2013-12-07
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多