Java是否保证getClass()返回的Class对象始终是同一个实例?

时间:2011-01-24 14:25:36

标签: java instance equality

  

可能重复:
  Does Java guarantee that Object.getClass() == Object.getClass()?

我注意到Eclipse为equals生成了这段代码:

public class MyClass {

    public boolean equals(Object obj) {
        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (getClass() != obj.getClass())
            return false;

        MyClass other = (MyClass) obj;

        // ...
    }

}

特别感兴趣的是这段代码:

if (getClass() != obj.getClass())
    return false;

代码假定Class返回的getClass()对象将所有对象的相同的实例(而不仅仅是等效的实例)同一类。也就是说,他们认为没有必要这样写:

if (getClass().equals(obj.getClass()))
    return false;

Java是否正式记录了getClass()方法的这种行为?

7 个答案:

答案 0 :(得分:11)

是的,只要两个类由同一个类加载器加载,类对象就会一样。

但如果不是这样,那么这两个类必须被视为不同,即使它们可能共享相同的名称和代码。 (这在使用多个类加载器时很容易遇到,因此值得记住。)

答案 1 :(得分:3)

  

Java是否正式记录了getClass()方法的这种行为?

是的。我还没有(但)找到一个明确的陈述,但有很多地方暗示......或者更强大......由javadocs。例如:

  1. Class.equals(Object)没有javadoc,这意味着Object.equals(Object)未被覆盖。

  2. Object.getClass()方法被指定为返回“此Object的运行时类”。 (注意它说“the”不是“a”。)javadoc还说“返回Class对象是被表示的类的静态同步方法锁定的对象”。如果任何类都有多个这样的对象,那么指定的同步机制将无法正常工作。

  3. Class.forName(...)方法被指定为返回“与具有给定字符串名称的类或接口关联的类对象”。 (再次注意,它说“不”是“a”。)

答案 2 :(得分:3)

这实际上取决于类加载器,因为我理解并不能保证:

http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#44459

  

表现良好的类加载器维护这些属性:

     
      
  • 给定相同的名称,一个好的类加载器应该总是返回相同的类对象。
  •   
  • 如果类加载器L1将类C的加载委托给另一个加载器L2,那么对于作为直接超类或C的直接超接口出现的任何类型T,或作为C中的字段类型,或作为C中方法或构造函数的形式参数的类型,或者作为C,L1和L2中方法的返回类型应该返回相同的类对象。
  •   
     

恶意类加载器可能违反这些属性。但是,它不能破坏类型系统的安全性,因为Java虚拟机可以防范这种情况。

答案 3 :(得分:2)

至少有(至少)这个事实的隐含文件(引自the JavaDoc,强调我的):

  

返回: Class对象,表示此对象的运行时类。

答案 4 :(得分:1)

我知道它不是一个实例,而是设计。如果类由不同的类加载器加载,它们将不是同一个实例,因为对于JVM,类是不同的。

答案 5 :(得分:1)

如果两个类实例相同,则可以确定对象的类型相同。

Altough我发现没有具体的参考来回答你的问题,只是为了完整性Java语言规范书,section #4.3.4说:

  

4.3.4引用类型相同时

     

两种参考类型是相同的   运行时类型if:

     
      
  • 它们都是类或两种接口类型,由   相同的类加载器,并具有相同的   二进制名称(第13.1节),在这种情况下   他们有时被认为是一样的   运行时类或相同的运行时   接口

  •   
  • 它们都是数组类型,它们的组件类型是相同的   运行时类型(§10)。

  •   

答案 6 :(得分:1)

这是一个工作示例,演示具有相同类名的类可能具有不同的Class个实例。但是equals表明类实例确实是不同的,即使这些类共享相同的名称并从同一资源加载。

准备:在默认包中创建一个简单的类:

public class SomeClass{}

将类文件(仅限!!)存储在类路径中不是的文件夹中(如/tmp)。

然后执行此方法:

public static void test() {
  try {
    URL[] urls = new URL[]{ new File("/tmp").toURL() };
    ClassLoader cl1 = URLClassLoader.newInstance(urls);
    ClassLoader cl2 = URLClassLoader.newInstance(urls);
    Class clazz1 = cl1.loadClass("SomeClass");
    Class clazz2 = cl2.loadClass("SomeClass");

    System.out.println("Same names?            " + clazz1.getName().equals(clazz2.getName()));
    System.out.println("clazz1 == clazz2:      " + (clazz1 == clazz2));
    System.out.println("clazz1.equals(clazz2): " + (clazz1.equals(clazz2)));
  } catch(Exception e) {
    e.printStackTrace();
  }
}