• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

StackOverflowError在等于双向对象的方法

java 来源:user 5次浏览

我必须对象客户端和顺序和这些对象都生活在双向关系,我尝试将它们写入文件,但我得到StackOverflowError。我得到这个错误,因为我的equals方法循环。StackOverflowError在等于双向对象的方法

我的班,我试图序列:

@Getter 
@Setter 
@AllArgsConstructor 
@NoArgsConstructor 
public class Client implements Serializable { 

    private Long id; 

    private String name; 

    private List<Order> orders = new ArrayList<>(); 

    public void addOrder(Order order) { 
     order.setClient(this); 
     orders.add(order); 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     Client client = (Client) o; 

     if (id != null ? !id.equals(client.id) : client.id != null) return false; 
     if (name != null ? !name.equals(client.name) : client.name != null) return false; 
     return orders != null ? orders.equals(client.orders) : client.orders == null; 
    } 

    @Override 
    public int hashCode() { 
     int result = id != null ? id.hashCode() : 0; 
     result = 31 * result + (name != null ? name.hashCode() : 0); 
     result = 31 * result + (orders != null ? orders.hashCode() : 0); 
     return result; 
    } 

    @Override 
    public String toString() { 
     return "Client{" + 
       "id=" + id + 
       ", name='" + name + '\'' + 
//    ", orders=" + orders.size() + 
       '}'; 
    } 
} 

@Getter 
@Setter 
@AllArgsConstructor 
@NoArgsConstructor 
public class Order implements Serializable { 

    private Long id; 

    private String name; 

    private Client client; 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     Order order = (Order) o; 

     if (id != null ? !id.equals(order.id) : order.id != null) return false; 
     if (name != null ? !name.equals(order.name) : order.name != null) return false; 
     return client != null ? client.equals(order.client) : order.client == null; 
    } 

    @Override 
    public int hashCode() { 
     int result = id != null ? id.hashCode() : 0; 
     result = 31 * result + (name != null ? name.hashCode() : 0); 
     result = 31 * result + (client != null ? client.hashCode() : 0); 
     return result; 
    } 

    @Override 
    public String toString() { 
     return "Order{" + 
       "id=" + id + 
       ", name='" + name + '\'' + 
       '}'; 
    } 
} 

@Data 
@AllArgsConstructor 
public class MapDataSource implements Serializable { 

    private final Map<Date, List<Client>> clients = new HashMap<>(); 
    private final Map<Date, List<Order>> orders = new HashMap<>(); 
} 

@Slf4j 
public class ObjectWriter { 
    private final String fileName = "data.obj"; 

    public void write(String fileName, MapDataSource mapDataSource) { 
     try (
       FileOutputStream fs = new FileOutputStream(fileName); 
       ObjectOutputStream oos = new ObjectOutputStream(fs) 
     ) { 
      oos.writeObject(mapDataSource); 
      log.info("Object has been written."); 
     } catch (IOException ioe) {} 
    } 
} 

@Slf4j 
public class ObjectReader { 
    private static final String fileName = "data.obj"; 

    public MapDataSource readObj(String fileName) { 
     MapDataSource mapDataSource = null; 
     try (
       FileInputStream fis = new FileInputStream(fileName); 
       ObjectInputStream ois = new ObjectInputStream(fis) 
     ) { 
      mapDataSource = ((MapDataSource) ois.readObject()); 
//   log.info("Read object: {}", mapDataSource); 
     } catch (IOException ioe) { 

     } catch (ClassNotFoundException classEx) { 
      System.out.println(); 
     } 
     return mapDataSource; 
    } 
} 

,当我尝试下面我得到的StackOverflowError运行代码:

String testFile = "testFile.obj"; 
     final DateTime time = new DateTime(2017, 12, 1, 10, 0); 
     final Client client1 = new Client(1L, "Client1", new ArrayList<>()); 
     final Order order1 = new Order(1L, "Order1", null); 
     final MapDataSource mapDataSource = new MapDataSource(); 
     mapDataSource.getClients().put(time.toDate(), new ArrayList<>()); 
     mapDataSource.getClients().get(time.toDate()).add(client1); 
     mapDataSource.getOrders().put(time.toDate(), new ArrayList<>()); 
     mapDataSource.getOrders().get(time.toDate()).add(order1); 

     new ObjectWriter().write(testFile, mapDataSource); 
     final MapDataSource found = new ObjectReader().readObj(testFile); 
     System.out.println(found); 

解决方案: MapDataSource需要已实施equals()hashcode()方法。


===========解决方案如下:

看起来你需要坐下来认真考虑它应该甚至对于两个客户或订单是否平等首先是什么意思。 Long id;让我怀疑你是否应该首先比较对象图。如果例如客户端具有唯一的ID,那么确保客户端是唯一的对象实例,然后完全消除该问题是有意义的。

如果你真的需要比较对象图,你可以使用类似下面的东西。我们使用一个IdentityHashMap来记录我们所看到的所有对象,然后如果我们检测到一个循环,我们只比较先前存储的计数器值,告诉我们这两个图形是否具有相同的循环。

ClientOrder需要共享代码(这样的地图,可以通过左右),所以你只覆盖两个equalsreturn ClientOrderEquality.equals(this, that)

import java.util.*; 

public final class ClientOrderEquality { 
    private ClientOrderEquality() {} 

    private static final class Counter { long value; } 

    public static boolean equals(Client lhs, Client rhs) { 
     return equals(lhs, new IdentityHashMap<>(), 
         rhs, new IdentityHashMap<>(), 
         new Counter()); 
    } 

    public static boolean equals(Order lhs, Order rhs) { 
     return equals(lhs, new IdentityHashMap<>(), 
         rhs, new IdentityHashMap<>(), 
         new Counter()); 
    } 

    private static boolean equals(Client   lhs, 
            Map<Object, Long> seenL, 
            Client   rhs, 
            Map<Object, Long> seenR, 
            Counter   counter) { 
     if (lhs == null || rhs == null) 
      return lhs == rhs; 
     Long countL = seenL.putIfAbsent(lhs, counter.value); 
     Long countR = seenR.putIfAbsent(rhs, counter.value); 
     if (countL != null || countR != null) 
      return Objects.equals(countL, countR); 
     counter.value++; 
     if (lhs == rhs) 
      return true; 
     if (!Objects.equals(lhs.id, rhs.id)) 
      return false; 
     if (!Objects.equals(lhs.name, rhs.name)) 
      return false; 
     if (lhs.orders.size() != rhs.orders.size()) 
      return false; 
     Iterator<Order> itL = lhs.orders.iterator(); 
     Iterator<Order> itR = rhs.orders.iterator(); 
     while (itL.hasNext() && itR.hasNext()) 
      if (!equals(itL.next(), seenL, itR.next(), seenR, counter)) 
       return false; 
     return true; 
    } 

    private static boolean equals(Order    lhs, 
            Map<Object, Long> seenL, 
            Order    rhs, 
            Map<Object, Long> seenR, 
            Counter   counter) { 
     if (lhs == null || rhs == null) 
      return lhs == rhs; 
     Long countL = seenL.putIfAbsent(lhs, counter.value); 
     Long countR = seenR.putIfAbsent(rhs, counter.value); 
     if (countL != null || countR != null) 
      return Objects.equals(countL, countR); 
     counter.value++; 
     if (lhs == rhs) 
      return true; 
     if (!Objects.equals(lhs.id, rhs.id)) 
      return false; 
     if (!Objects.equals(lhs.name, rhs.name)) 
      return false; 
     return equals(lhs.client, seenL, rhs.client, seenR, counter); 
    } 
} 

我认为,如果你想实际使用的代码,你需要改变它使用你使用任何的getter命名,写一个hashCode实现。如果您延长ClientOrder,您还需要正确考虑子类型。


版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)