按类型或类名比较两个类

时间:2012-05-05 19:29:19

标签: java oop

需要根据它们实现的类比较两个对象吗?何时使用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)

7 个答案:

答案 0 :(得分:31)

使用class.equals()

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

或者,因为每个类都像一个单例 - 每个类加载器每个类只有一个实例,并且大多数JVM只有一个类加载器 - 你甚至可以使用身份比较:

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

答案 1 :(得分:19)

  

这种比较两种对象类类型(名称)的方法有什么区别吗?

是。如果两个类由不同的ClassLoader加载,则它们可能具有相同的名称。

"The basics of Java class loaders"

  

最简单的是,类加载器创建一个由字符串名称引用的类主体的平面名称空间。

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

  

这意味着可以将两个具有相同名称的类同时加载到VM中,前提是它们具有两个单独的ClassLoader


  

何时使用getClass()和何时getClass().getName()进行比较?

如果您想知道两个对象是否属于同一类型,您应该使用equals方法来比较这两个类 - 第一个选项。

我无法想象你为什么要这样做,但是如果你想知道具有不同具体类型的两个对象是否具有相同的完全限定名称的类型,那么你可以使用第二个。如果您在Java的上下文中不理解“具体类型”和“完全限定名称”,那么您就不会为java编写类型分析代码,因此您不想这样做。

答案 2 :(得分:3)

我遇到了使用.equals比较两个类的问题。上面提供的解决方案并不完全准确。类没有实现Comparable。

类引用不一定是JVM中的真正单例,因为您可以拥有多个ClassLoader。

我正在编写一个Maven插件,它在编译后从bean中挖出注释。该插件有一个类加载器,我有自己的类加载器。当比较来自不同加载器的两个相同名称的类时,比较将失败。

Object.equals的实现如下所示:

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

所以你将比较参考文献。

如果您正在比较课程,并且您确定只会涉及一个类加载器,您可以安全地使用.equals或c1 == c2,但如果您不确定是否应按名称进行比较:

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

答案 3 :(得分:1)

事实上,按名称比较受信任的类是一个弱点。 请参阅https://cwe.mitre.org/data/definitions/486.html

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

是比较类的正确方法

if (nextMonster.getClass().equals(monster.getClass()))
@ pohemian提到的

应该仍然可以正常工作

答案 4 :(得分:1)

实现相同目标的另一种方法是覆盖子类中的哈希码。

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

现在,如果实现/子类具有相同的具体类型,则equals将返回。

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

答案 5 :(得分:0)

您可以使用Class的内置方法:

if(nextMonster.getClass().isAssignableFrom(monster.getClass()))

答案 6 :(得分:0)

如果要比较的数组,请在下面使用

array.getClass().getComponentType() == X.class