35

需要根据它们实现的类来比较两个对象吗?何时比较使用getClass()和何时getClass().getName()?这种比较两个 Objects 类类型(名称)的方法有什么区别吗?

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)
4

7 回答 7

35

使用class.equals()

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

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

if (nextMonster.getClass() == monster.getClass())
于 2012-05-05T19:33:54.690 回答
21

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

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

“Java 类加载器的基础知识”

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

“Eclipse - 两个虚拟机(和许多类加载器)的故事”

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


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

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

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

于 2012-05-05T19:33:43.627 回答
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()) {
   ...
}
于 2015-10-07T17:51:00.557 回答
1

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

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

是比较类的正确方法

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

由于@Bohemian提到的同样原因应该仍然有效

于 2015-12-13T13:33:31.100 回答
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"
    }
}

现在,如果实现/子类具有相同的具体类型,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
于 2016-07-01T11:15:56.620 回答
-1

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

if(nextMonster.getClass().isAssignableFrom(monster.getClass()))
于 2020-04-17T11:22:32.570 回答
-1

如果您有一个数组用于getClass().getComponentType()比较其内容类型

jshell> var array1 = new int[15]
array1 ==> int[15] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

jshell> var array2 = new int[10]
array2 ==> int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

jshell> array1.getClass() == array2.getClass()
$7 ==> true

jshell> array1.getClass().getComponentType()
$8 ==> int

jshell> array1.getClass().getComponentType() == int.class
$12 ==> true
于 2020-11-05T07:19:56.577 回答