2012-10-31 38 views
12

Tôi có một lớp cơ sở đơn giản, sau này được mở rộng bởi nhiều lớp riêng biệt, có khả năng giới thiệu các trường mới, nhưng không nhất thiết. Tôi đã định nghĩa một phương thức equals trong lớp cơ sở, nhưng cũng overriden rằng đối với một vài lớp con. Có thể kết hợp các định nghĩa trong cơ sở/lớp con không? Trong trường hợp của tôi nó là để tránh trùng lặp mã kiểm tra các lĩnh vực tương tự.Java - bằng phương pháp trong lớp cơ sở và trong các lớp con

+6

Bạn có thể giải thích ý bạn bằng cách trộn các định nghĩa hay không. Cảm ơn. – tjg184

+0

Có một định nghĩa trong lớp cơ sở, có thể/không thể được ghi đè lên. Tôi có nghĩa là để nói "cách tiếp cận trộn của lớp cơ sở xác định vs phân lớp xác định" – Bober02

Trả lời

22

Hãy xem "Implementing equals() To Allow Mixed-Type Comparison" từ Angelika Langer.

Dưới đây là một lời giải thích ngắn gọn về một số vấn đề và giải pháp khả thi:

Các bằng hợp đồng nói (giữa những người khác):

Nó là đối xứng: đối với bất kỳ giá trị tham chiếu không null x và y , x.equals (y) sẽ trả về true nếu và chỉ khi y.equals (x) trả về true.

Điều đó có nghĩa là bạn có thể gặp vấn đề nếu lớp con của bạn giới thiệu trường mới và bạn đang so sánh đối tượng của lớp cơ sở (hoặc một lớp con khác không ghi đè bằng) với đối tượng của lớp con này .

ĐỪNG làm như sau:

class BaseClass { 
    private int field1 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof BaseClass) { 
      return field1 == ((BaseClass) obj).field1; 
     } 
     return false; 
    } 
} 

class BadSubClass extends BaseClass { 
    private int field2 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof BadSubClass) { 
      return super.equals(obj) 
        && field2 == ((BadSubClass) obj).field2; 
     } 
     return false; 
    } 
} 

vì bạn nhận được

BaseClass baseClass = new BaseClass(); 
BadSubClass subClass = new BadSubClass(); 

System.out.println(baseClass.equals(subClass)); // prints 'true' 
System.out.println(subClass.equals(baseClass)); // prints 'false' 

Một giải pháp khả thi:

Thay -Kiểm tra instanceof với một so sánh lớp:

obj != null && obj.getClass() == getClass() 

Với giải pháp này, đối tượng của BaseClass sẽ không bao giờ bằng với đối tượng của bất kỳ lớp con nào.

Nếu bạn tạo một SubClass mà không có một @Override của phương pháp equals, hai SubClass -objects có thể bình đẳng với nhau (nếu kiểm tra BaseClass.equals quyết định như vậy) ra khỏi hộp, nhưng một SubClass -object sẽ không bao giờ bằng a BaseClass -object.

Một thực hiện tốt có thể là như sau:

class BaseClass { 
    private int field1 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj != null && obj.getClass() == getClass()) { 
      return field1 == ((BaseClass) obj).field1; 
     } 
     return false; 
    } 
} 

class GoodSubClass extends BaseClass { 
    private int field2 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof GoodSubClass) { 
      return super.equals(obj) && field2 == ((GoodSubClass) obj).field2; 
     } 
     return false; 
    } 
} 

hãy tham khảo bài viết nêu trên cho các vấn đề nâng cao hơn và giải pháp của họ.

+0

Cảm ơn bạn đã liên kết bài viết Angelika Langer. Mặc dù điều này vi phạm nguyên tắc thay thế Liskov, AFAIK. Xem lại "Java hiệu quả" của Joshua Block. (Tôi chưa đọc toàn bộ bài báo.) – Puce

+1

có vấn đề gì với o.getClass()! = This.getClass()? – Mukul

+0

@Mukul Tôi nghĩ rằng nó thực sự tốt hơn vì bạn tránh sự cần thiết phải ghi đè phương thức equals nếu bạn không thực hiện kiểm tra bổ sung cộng với bạn có thể gọi 'super.equals()' mà không phá vỡ mọi thứ. Tôi vừa gửi một bản chỉnh sửa theo – Qw3ry

0

Tôi nghĩ rằng điều đó hoàn toàn miễn là bạn tuân theo các hợp đồng eqauls()hashcode().

0

Bạn có thể sử dụng phương pháp super() để gọi phương thức của lớp mà bạn đang mở rộng để ngăn chặn bất kỳ nhu cầu của việc lặp lại code

public class BaseClass { 
    public boolean equals(BaseClass other) { 
    return (other.getBlahblah() == this.Blahblah && .....); 
    } 
} 

public class DerivedClass extends BaseClass { 
    public boolean equals(DerivedClass other) { 
    return (super(other) && other.getNewAttribute() == this.NewAttribute.....); 
    } 
} 
+1

+1 cho lời khuyên để gọi siêu đầu tiên. Một lưu ý - nó không phải là một mã Java hợp lệ, nó sẽ được mát mẻ để sửa nó (tôi hiểu nó có thể chỉ là một mã giả như một ví dụ). –

+0

Cảm ơn. Tôi chỉ cắt nó ra mà không làm kiểm tra trên hầu hết các công cụ. Nó đã được một chút kể từ khi tôi đã làm Java và phải đã meshed một số cú pháp khác và các cuộc gọi bên trong nó. – Grambot

+0

Bạn không ghi đè đối tượng bằng nhưng thay vì quá tải nó –

0

Khá một cách tiếp cận hợp lệ. Vấn đề là ở một trong các lớp con của bạn, phải giữ nguyên định nghĩa bằng bằng bị ràng buộc bởi cha mẹ của nó. Khác bạn có một hàm bằng bằng, có thể gây ra một số kịch bản rất độc đáo trong thời gian chạy.

2

Không, không thể tuân thủ hợp đồng tương đương khi giới thiệu các trường mới có liên quan đến phương thức equals. Xem "Java hiệu quả" của Joshua Bloch để biết thêm thông tin.

Edit:

Tôi không có cuốn sách trong tay ngay bây giờ, nhưng tôi nghĩ rằng nó là ok nếu lớp cơ sở trừu tượng là/không thể được khởi tạo.

+0

+1 vì tham chiếu everseen cho Bloch. Và bởi vì đó là sự thật – Jerome

+0

nó là trừu tượng :) – Bober02

0

Tôi đoán, Điều đó hoàn hảo để cung cấp triển khai phương pháp equals(Object obj)hashCode() trong superclassJava đã làm. Chúng ta đều biết rằng Java cung cấp triển khai phương pháp hashCode() and equals(Object obj) trong lớp cơ sở java.lang.Object và khi chúng tôi yêu cầu chúng tôi override chúng trong số class của chúng tôi.

0

Trong khi những điều sau đây không xử lý mọi trường hợp, tôi thấy nó khá thực tế. Tôi đã sử dụng nó nhiều lần khi tôi có cả SuperClass và SubClass. Tôi không muốn so sánh chúng, nhưng tôi cũng không muốn thực hiện lại tất cả các SuperClass equals() cho SubClass. Nó xử lý:

  • a.equals (b) == b.equals (a)
  • Không trùng lặp mã so sánh lĩnh vực
  • Dễ dàng khái quát hóa cho bất kỳ độ sâu lớp con
  • Subclass.equals (SuperClass) == false
  • Superclass.equals (lớp con) == false

Mã dụ

// implement both strict and asymmetric equality 
class SuperClass { 
    public int f1; 
    public boolean looseEquals(Object o) { 
     if (!(o instanceof SuperClass)) return false; 
     SuperClass other = (SuperClass)o; 
     return f1 == other.f1; 
    } 
    @Override public boolean equals(Object o) { 
     return looseEquals(o) && this.getClass() == o.getClass(); 
    } 
} 
class SubClass extends SuperClass { 
    public int f2; 
    @Override public boolean looseEquals(Object o) { 
     if (!super.looseEquals(o)) return false; 
     if (!(o instanceof SubClass)) return false; 
     SubClass other = (SubClass)o; 
     return f2 == other.f2; 
    } 
    // no need to override equals() 
} 
Các vấn đề liên quan