2012-05-05 3 views
21

Нужно сравнить два объекта на основе класса, который они реализуют? Когда сравнивать, используя getClass() и когда getClass().getName()? Существует ли разница между этими подходами для сравнения двух типов (имен) классов объектов?Сравнение двух классов по его типам или именам классов

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


А что?

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

вам нужно .equals с GetClass ли? Вернуть класс возвращает объект, отличный от String. +1 интересный вопрос. – jmort253

ответ

18

Есть ли какая-то разница между этим подходит для сравнения типов двух объектов класса (имена)?

Да. Два класса могут иметь одно и то же имя, если они загружены разными ClassLoader s.

"The basics of Java class loaders" говорит

В простейшем случае класс погрузчик создает плоское пространство имен класса органов, на которые ссылается именем строки.

"Eclipse - a tale of two VMs (and many classloaders)" говорит

Это означает, что можно иметь два класса с тем же именем загруженного в виртуальную машину сразу, при условии, что они имеют два отдельных загрузчиков классов


Когда сравнивать, используя getClass() и когда getClass().getName()?

Если вы хотите знать, являются ли два объекта одного и того же типа, вы должны использовать метод equals сравнить два класса - первый вариант.

Я не могу представить, почему вы хотите это сделать, но если вы хотите знать, имеют ли два объекта с разными конкретными типами с одним и тем же полным именем, вы можете использовать второй. Если вы не понимаете «конкретные типы» и «полностью квалифицированные имена» в контексте Java, вы не пишете код анализа типа для Java, поэтому не хотите.

28

Использование class.equals():

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

или, потому что каждый класс как синглтон - есть только один экземпляр каждого класса в JVM - вы можете даже использовать сравнение идентичности:

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

I столкнулся с проблемой сравнения двух классов с использованием .equals. Вышеприведенное решение не совсем точно. Класс не реализует Comparable.

Ссылки на классы не обязательно являются истинными синглетонами внутри JVM, потому что у вас может быть несколько ClassLoaders.

Я писал плагин Maven, который копал аннотации из фасоли после компиляции. У плагина был один загрузчик классов, и у меня был свой собственный загрузчик классов. При сравнении двух классов одного и того же имени с разными загрузчиками сравнение потерпит неудачу.

Реализация Object.equals выглядит следующим образом:

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

Так вы будете сравнивающие ссылки.

Если вы сравниваете классы, и вы знаете наверняка там будет только один загрузчик классов участвует вы можете безопасно использовать .equals или c1 == c2, но если вы не уверены, что вы должны сравнить по имени:

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

Зачем вам нужно сравнивать классные имена от двух разных классов-загрузчиков? Это действительный сенарио? Приведите пример, когда вам нужно сделать это в реальной жизни. –

+0

Мое приложение было очень необычным. Я делаю плагин Maven, который создает документацию для конечных точек REST. Я хотел использовать аннотации JAX (или Spring) для создания HTML-документов. Используемый плагин Maven загружал все классы с использованием класса JarClassLoader, а плагин Maven запускал свой код в загрузчике классов. Я пытался выяснить, присутствует ли аннотация в классе Jar, но сравнение не удалось, хотя они были теми же именами классов. Я закончил тем, что отказался от проекта. –

1

На самом деле сравнение доверенного класса по имени является слабостью. См https://cwe.mitre.org/data/definitions/486.html

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

правильный способ сравнить классы

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

должно работать по той же причине @Bohemian упомянутого

0

Другой способ добиться того же будет переопределив в хэш-код подкласс.

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" 
    } 
} 

Теперь равные значения возвращаются, если реализации/подклассы имеют один и тот же конкретный тип.

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 
Смежные вопросы