gpt4 book ai didi

java - 双向对象的 equals 方法中的 StackOverflowError

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:09:37 24 4
gpt4 key购买 nike

我必须对象 Client 和 Order,这些对象存在于双向关系中,我尝试将它们写入文件,但我得到 StackOverflowError。我收到此错误是因为我的 equals 方法是循环的。

我尝试序列化的类:

@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 需要共享代码(这样映射就可以传递),所以你只需覆盖 equals返回 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,您还需要正确考虑子类型。

关于java - 双向对象的 equals 方法中的 StackOverflowError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47614741/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com