Java中子类DiscountProduct的相等性测试实现咨询
Hey there! Let's sort out this equality testing issue step by step. First, your existing code has some critical bugs that are breaking equality checks entirely—let's fix those first, then implement the correct equals method for DiscountProduct.
First: Fix the Broken Equality Logic in Product and Order
1. Product Class's equals Method (Major Bug!)
Right now, your Product.equals incorrectly casts the input obj to Order—that's a huge mistake! The equals method for Product should compare other Product instances, not Orders. Here's the corrected version:
import java.util.Objects; public class Product implements Comparable<Product> { private String productCode; private String description; private int unitPrice; //pence public Product(String productCode, String description, int unitPrice) { this.productCode = productCode; this.description = description; this.unitPrice = unitPrice; } // Corrected equals method for Product @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; // Strict type check to preserve symmetry Product other = (Product) obj; return unitPrice == other.unitPrice && productCode.equals(other.productCode) && description.equals(other.description); } // Required by Java's Object contract when overriding equals @Override public int hashCode() { return Objects.hash(productCode, description, unitPrice); } // Implement Comparable as needed (omitted for brevity) @Override public int compareTo(Product o) { return this.productCode.compareTo(o.productCode); } }
2. Order Class's equals Method (Bug Fix)
Your Order.equals has a mistake: product.equals(obj) is passing the entire Order object to Product's equals, which is wrong. You need to compare the product field of the other Order. Also, always override hashCode when you override equals!
import java.util.Objects; public class Order implements Comparable<Order> { private int quantity; private Product product; public Order(int quantity, Product product) { this.quantity = quantity; this.product = product; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Order other = (Order) obj; return quantity == other.quantity && Objects.equals(product, other.product); // Compare the two Product instances correctly } @Override public int hashCode() { return Objects.hash(quantity, product); } public Product getProduct() { return product; } // Implement Comparable as needed (omitted for brevity) @Override public int compareTo(Order o) { return this.product.compareTo(o.product); } }
Now: Implement DiscountProduct's equals Method
For DiscountProduct, we need to extend the equality check to include the discountRate field, while still honoring the parent class's equality logic. Here's how to do it correctly:
import java.util.Objects; public class DiscountProduct extends Product { private double discountRate; public DiscountProduct(String productCode, String description, int unitPrice, double discountRate) { super(productCode, description, unitPrice); this.discountRate = discountRate; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; // First verify parent class fields are equal if (!super.equals(obj)) return false; // Now compare DiscountProduct-specific field DiscountProduct other = (DiscountProduct) obj; // Use Double.compare to avoid floating-point precision issues return Double.compare(other.discountRate, discountRate) == 0; } @Override public int hashCode() { return Objects.hash(super.hashCode(), discountRate); } // Optional getter for discountRate (useful for other logic) public double getDiscountRate() { return discountRate; } }
Key Notes:
- Strict Type Check: Using
getClass() != obj.getClass()instead ofinstanceofensures symmetry—ifa.equals(b)is true,b.equals(a)must also be true. Usinginstanceofwould break this contract (a Product might match a DiscountProduct, but the reverse wouldn't hold). - Floating-Point Equality: Never use
==directly fordoublevalues—Double.compare()handles precision edge cases properly. - HashCode Contract: Overriding
hashCodealongsideequalsis mandatory—this ensures consistent behavior in collections likeHashMaporHashSet.
How This Works for Your Use Case
When comparing two Order instances with DiscountProducts:
- The Order's
equalschecks the quantity, then callsproduct.equals(otherProduct). - Since the product is a
DiscountProduct, it first validates all parentProductfields viasuper.equals(), then compares thediscountRate.
This ensures full equality checking across the entire class hierarchy.
内容的提问来源于stack exchange,提问作者Muhammad Mansha

