2016-04-26 88 views
0

所以我有一些存储在MySQL数据库中的朋友系统的数据,以及一些API来检索Java对象中的数据。 (MPlayer)包含诸如用户名,在线状态,朋友(由“:”分隔的ID)之类的东西。 MPlayer对象将玩家的唯一ID作为构造函数。我该如何解决这个递归的StackOverFlowException错误?

创建时以及调用reload()方法时,数据保存在对象中。这不是每次我想获得像用户名这样的东西时访问数据库。原因是我需要将数据放到一个循环中才能显示在GUI上,而且我显然不希望每帧都下载数据。相反,我只是每6秒左右使用重载方法。

其中一个函数是getFriends()并返回MPlayer的列表。该列表在MPlayer对象创建时存储。问题是,当每个MPlayer朋友被创建时,它会为他们的朋友创建一个列表,然后为他们的朋友创建一个列表,最后由于递归而结束StackOverFlowException。

什么是避免错误的好方法?

代码中的问题:

MPlayer的构造函数/ load方法:

public MPlayer(String player){ 
    this.uuid = player; 
    try { 
     st.setString(1, uuid); 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 
    this.reload(); 
} 

public void reload(){ 
    try { 
     ResultSet set = st.executeQuery(); 
     if(set.next()){ 
      if(set.getString("server").equals("none")){ 
       isConnected = false; 
      }else{ 
       isConnected = true; 
      } 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 

    try { 
     ResultSet set = st.executeQuery(); 
     if(set.next()){ 
      this.serverIP = set.getString("server"); 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 



    try { 

     ResultSet set = st.executeQuery(); 
     if(set.next()){ 
      this.username = set.getString("username"); 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 


    try { 
     ResultSet get = st.executeQuery(); 
     if(get.next()){ 
      this.online = get.getBoolean("status"); 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 
    try { 


     List<MPlayer> list = new ArrayList<MPlayer>(); 
     ResultSet get = st.executeQuery(); 
     if(get.next()){ 
      for(String str : get.getString("friends").split(":")){ 
       if(!str.equalsIgnoreCase("none")){ 
        MPlayer player = new MPlayer(str); 
        if(player.isOnline()){ 
         list.add(0,player); 
        }else{ 
         list.add(player); 
        } 
       } 
      } 

     } 
     this.friends = list; 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 


    this.settings = new Settings(this); 


    PreparedStatement state = Main.getPreparedStatement("SELECT * FROM updates WHERE uuid=?"); 
    try { 
     state.setString(1, this.getUUID()); 
     ResultSet set2 = state.executeQuery(); 
     List<StatusUpdate> updates = new ArrayList<StatusUpdate>(); 

     while(set2.next()){ 
      updates.add(new StatusUpdate(set2.getInt(1))); 
     } 
      Collections.sort(updates, new Comparator<StatusUpdate>() { 
       @Override 
       public int compare(StatusUpdate r1, StatusUpdate r2) { 

        return -1 * r1.getDate().compareTo(r2.getDate()); 
       } 
      }); 

     this.updates = updates; 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 


    List<StatusUpdate> updates = new ArrayList<StatusUpdate>(); 

    for(MPlayer p : this.getFriends()){ 
     updates.addAll(p.getStatusUpdates()); 

    } 
    updates.addAll(this.getStatusUpdates()); 
    Collections.sort(updates, new Comparator<StatusUpdate>() { 
     public int compare(StatusUpdate m1, StatusUpdate m2) { 

      return -1 * m1.getDate().compareTo(m2.getDate()); 
     } 
    }); 
    this.timeline = updates; 



} 
+1

请发布您的代码和确切的错误。 [关于SO的问题](http://stackoverflow.com/help/how-to-ask)。 – Dresden

+0

这里的问题是,你正在从'reload'函数中调用'MPlayer player = new MPlayer(str)',但是在'MPlayer'的构造函数中,你也调用'this.reload();'这也会调用'MPlayer播放器=新的MPlayer(str);'所以循环是无限的 - 我认为第一步应该是重构你的代码 - 这不是一个好主意,你的'reload'函数做的太多了...... – ishmaelMakitla

回答

0

答案显然是 “退出,无终止递归这样做”。

你不想在朋友列表上无限的关闭 - 但你想要什么?只是朋友的名单?在这种情况下,也许你需要一个单独的对象类型,比如“FriendList”。在创建这个时,你只需列出好友ID;不要加载朋友记录,直到它被明确访问。

另一种方法是编码要激活的级别数,使其成为对象加载的参数。对于isntance,加载深度为N = 2的主MPlayer。对于主要的每个朋友,加载深度为N-1。当你点击0时,列出ID而不加载记录(如上所述)。

这是否让您朝着解决方案迈进?

+0

我明白了。某种只读选手对象?谢谢你,你是少数几个人不是“你做得完全错误,重做你的代码,然后再回来”的例子之一。 –

+0

你很受欢迎。是的,只读是查看它的一种方式。最重要的是,您只需要将衍生案例与主要派生案例分开,以打破无限递归。 – Prune

+0

我同意其他人的看法,认为你的代码似乎不是“自然的方式”去思考它,但我认为你比我们更了解你的问题空间。 :-)例如,您的方法可能会支持您尚未实现的功能。 – Prune

相关问题