2012-05-05 38 views
21

Có cần so sánh hai đối tượng dựa trên lớp mà chúng triển khai không? Khi so sánh sử dụng getClass() và khi nào getClass().getName()? Có sự khác nhau nào giữa phương pháp này để so sánh hai loại lớp (tên) của đối tượng không?So sánh hai loại theo loại hoặc tên lớp

public abstract class Monster { ... } 
public class MonsterTypeOne extends Monster { ... } 
public class MonsterTypeTwo extends Monster { ... } 

    Monster monster = MonsterTypeOne(); 
    Monster nextMonster = MonsterTypeTwo(); 


if(nextMonster.getClass().getName().equals(monster.getClass().getName()))// #1 

if(nextMonster.getClass().equals(monster.getClass()))// #2 

EDIT 1


gì về?

nextMonster.getClass().equals(MonsterTypeOne.class) 
+0

Bạn có cần Equals với getClass? Nhận lớp trả về một đối tượng không phải String mà tôi tin. +1 câu hỏi thú vị. – jmort253

Trả lời

18

Có bất kỳ sự khác biệt giữa điều này phương pháp tiếp cận để so sánh các loại hai đối tượng lớp (tên)?

Có. Hai lớp có thể có cùng tên nếu chúng được tải bởi các khác nhau ClassLoader s.

"The basics of Java class loaders" nói

Tại đơn giản nhất, một bộ nạp lớp tạo ra một không gian tên phẳng của các cơ quan lớp được tham chiếu bởi một tên chuỗi.

"Eclipse - a tale of two VMs (and many classloaders)" nói

Điều đó có nghĩa nó có thể có hai lớp có cùng tên nạp vào một máy ảo cùng một lúc, với điều kiện là họ có hai classloaders riêng


Khi nào cần so sánh sử dụng getClass() và khi getClass().getName()?

Nếu bạn muốn biết hai đối tượng có cùng loại, bạn nên sử dụng phương pháp equals để so sánh hai lớp - tùy chọn đầu tiên. Tôi không thể tưởng tượng tại sao bạn muốn làm điều này, nhưng nếu bạn muốn biết liệu hai đối tượng có các loại cụ thể khác nhau có các loại có cùng tên đủ điều kiện hay không, thì bạn có thể sử dụng tên thứ hai. Nếu bạn không hiểu "các loại cụ thể" và "tên đủ điều kiện" trong ngữ cảnh của Java thì bạn không viết mã phân tích kiểu cho java, do đó bạn không muốn.

28

Sử dụng class.equals():

if (nextMonster.getClass().equals(monster.getClass())) 

hoặc, bởi vì mỗi lớp cũng giống như một singleton - chỉ có một thể hiện của mỗi lớp mỗi JVM - thậm chí bạn có thể sử dụng một so sánh sắc:

if (nextMonster.getClass() == monster.getClass()) 
3

tôi gặp phải vấn đề khi so sánh hai lớp bằng cách sử dụng .equals. Giải pháp được cung cấp ở trên không hoàn toàn chính xác. Lớp không thực hiện Comparable.

Tham khảo lớp học không nhất thiết phải là những đơn vị thực sự trong JVM vì bạn có thể có nhiều Trình nạp lớp.

Tôi đã viết một plugin Maven đang đào chú thích ra khỏi hạt sau khi biên dịch. Plugin có một trình nạp lớp và tôi có trình nạp lớp của riêng mình. Khi so sánh hai lớp cùng tên với các trình nạp khác nhau, phép so sánh sẽ thất bại.

Việc thực hiện Object.equals trông như thế này:

public boolean More ...equals(Object obj) { 
     return (this == obj); 
} 

tài liệu tham khảo Vì vậy, bạn sẽ được so sánh.

Nếu bạn đang so sánh các lớp học và bạn biết chắc chắn có sẽ chỉ là một classloader tham gia, bạn có thể an toàn sử dụng Equals hoặc c1 == c2 nhưng nếu bạn không chắc chắn bạn nên so sánh theo tên:

if(c1.getName().equals(c2.getName()) { 
    ... 
} 
+0

tại sao bạn cần phải so sánh tên lớp từ hai trình nạp lớp khác nhau? Đó có phải là một senario hợp lệ không? Hãy cho tôi một ví dụ khi bạn cần phải làm điều đó trong cuộc sống thực. –

+0

Đơn đăng ký của tôi rất khác thường. Tôi đã tạo một plugin Maven để tạo tài liệu cho các điểm cuối REST. Tôi muốn sử dụng chú thích JAX (hoặc Spring) để tạo tài liệu HTML. Plugin Maven được sử dụng sẽ tải tất cả các lớp bằng cách sử dụng lớp JarClassLoader và plugin Maven chạy mã của nó trong trình nạp lớp của trình xây dựng. Tôi đã cố gắng để xem nếu các chú thích đã có mặt trong lớp của Jar nhưng so sánh thất bại mặc dù họ là cùng một tên lớp. Tôi đã từ bỏ dự án. –

1

Như một vấn đề của thực tế so sánh lớp đáng tin cậy theo tên là một điểm yếu. Tham khảo https://cwe.mitre.org/data/definitions/486.html

if (nextMonster.getClass() == monster.getClass()) 

là cách chính xác để so sánh lớp

if (nextMonster.getClass().equals(monster.getClass())) 

vẫn nên làm việc với cùng lý do @Bohemian nêu

0

Một cách khác để đạt được như vậy sẽ bằng cách ghi đè hashcode trong lớp con.

public interface Parent { 
} 

public static class Child1 implements Parent{ 
    private String anyfield="child1"; 

    @Override 
    public int hashCode() { 
     //Code based on "anyfield" 
    } 

    @Override 
    public boolean equals(Object obj) { 
     //equals based on "anyfield" 
    } 
} 

public static class Child2 implements Parent{ 
    private String anyfield="child2"; 

    @Override 
    public int hashCode() { 
     //Code based on "anyfield" 
    } 

    @Override 
    public boolean equals(Object obj) { 
     //equals based on "anyfield" 
    } 
} 

Bây giờ, giá trị bằng sẽ trả về nếu triển khai/lớp con có cùng loại bê tông.

public static void main(String args[]){ 
    Parent p1=new Child1(); 
    Parent p2=new Child1(); 
    Parent p3=new Child2(); 
    System.out.println("p1 and p2 are same : "+p1.equals(p2)); 
    System.out.println("p2 and p3 are same : "+p2.equals(p3)); 
} 

Output-

p1 and p2 are same : true 
p2 and p3 are same : false 
Các vấn đề liên quan