Подтвердить что ты не робот

Сравнение двух классов по типам или именам классов

Нужно ли сравнивать два объекта на основе класса, который они реализуют? Когда сравнивать 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

ИЗМЕНИТЬ 1


Как насчет:?

nextMonster.getClass().equals(MonsterTypeOne.class)
4b9b3361

Ответ 1

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

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

"Основы загрузчиков классов Java" сообщает

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

"Eclipse - рассказ о двух виртуальных машинах (и многих загрузчиках классов)" сообщает

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


Когда сравнивать getClass() и getClass().getName()?

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

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

Ответ 2

Используйте class.equals():

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

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

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

Ответ 3

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

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

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

Реализация Object.equals выглядит так:

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

Итак, вы будете сравнивать ссылки.

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

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

Ответ 4

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

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

- правильный способ сравнения классов

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

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

Ответ 5

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

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));
}

Вывод -

p1 and p2 are same : true
p2 and p3 are same : false