【问题标题】:Is Class<T> immutable in Java, also known as, is Class<T> a safe key for HashMap?Java中Class<T>是不可变的,也称为Class<T>是HashMap的安全键吗?
【发布时间】:2013-02-21 03:01:26
【问题描述】:

我已经在网上潜伏了一段时间,但还没有找到答案。 有人在 SO 上提到 Class&lt;T&gt; 作为关键(我认为),但我再也找不到该帖子了。 无论如何,这个问题应该得到一个正确的答案(如果上面有一千个帖子,请道歉)。

Class&lt;T&gt; 是不可变的吗?是否可以安全有效地用作密钥(常量hashCode() over execution)?

我的猜测是肯定的,因为类定义在运行时不会改变。但我不太确定...谢谢!

编辑:谈论 Java。

【问题讨论】:

  • 习惯上用您使用的语言标记问题。
  • hashCode 让我想到了 Java。 Class&lt;T&gt;.
  • 是的,简而言之,Class 实例是不可变的。

标签: java hashmap immutability hashcode java.lang.class


【解决方案1】:

Java 中的不可变对象是不能通过任何正常(非反射)执行路径更改其内部状态的对象。这意味着:

  • 该类没有定义改变其内部状态的可访问方法
  • 该类的设计方式是防止子类改变其内部状态

Java Class 类满足这些要求:

  • 它没有提供改变其内部状态的方法。
  • 类本身是final,不能子类化。

当然,实际的类定义是由 JVM 通过类加载器加载的,一旦定义,就会在该 JVM 的生命周期内设置并且不会改变。

【讨论】:

  • 好的,谢谢。我继续使用 Grep Code 并检查了 openjdk 实现。那里有三个静态字段。我似乎没有看到 hashCode() 实现。还有一些本地调用。
  • 考虑到@Evgeniy Dorofeev 在下面的回答,我会接受这个,因为它明确回答。谢谢。
【解决方案2】:

1)我不确定它是否可以称为不可变,至少在经典意义上,看看

public final class Class<T>
    ...
    native void setSigners(Object[] signers);
    ...
    native void setProtectionDomain0(java.security.ProtectionDomain pd);
    ...
    void setAnnotationType(AnnotationType type) 
    ...

2) 我们可以在 HashMap 中使用它,Class 是一个单例,它的 hashCode 和 equals 是基于它的身份,需要注意的是一个类在不同的类加载器中会有不同的实例,所以 MyClass.class from classloader1 != MyClass .class 来自 classloader2

【讨论】:

  • 我们可以安全地假设这些方法不是在运行时随机调用,而是在类加载时调用吗?可能是的......
  • 这些方法是包私有的,它们没有 API,我们不能对它们的行为做出假设。 Still Class 在基于哈希的集合中是 100% 安全的,它是最终的,并且从 Object 继承 hashCode / equals
【解决方案3】:

ClasshashCode() 方法未被覆盖,但 JDK 指定了以下关于 getClass() 方法的内容:

public final Class<?> getClass()

返回此对象的运行时类。 返回的Class对象是被代表类的static synchronized方法锁定的对象。

实际结果类型是Class&lt;? extends |X|&gt;,其中|X| 是调用getClass 的表达式的静态类型的擦除。例如,此代码片段中不需要强制转换:

Number n = 0;
Class<? extends Number> c = n.getClass(); 

因此对于任何实例 T objT obj2obj.getClass()obj2.getClass() 返回相同的(不可变的)Class&lt;T&gt; 对象。

但是,请注意类型擦除:LinkedList&lt;T&gt; l1LinkedList&lt;U&gt; l2 并非如此,因为两者都将返回类型擦除类 Class&lt;LinkedList&gt;,而不是特定于 TClass&lt;LinkedList&lt;T&gt;&gt; .

【讨论】:

  • 不错。这只是好奇,因为对于我的第二个问题(它是否是 HashMap 的好键),我最好询问 Object 是否是不可变的,而不是 Class。等等……我说的对吗? :S
  • 好吧,一切都是Object。我只是说对于某些T aa.getClass() 返回一个与任何T b 相同的Class&lt;T&gt; klazz。但是,LinkedList&lt;T&gt; l1LinkedList&lt;U&gt; l2 则不是这样,因为两者都将返回类型擦除类 Class&lt;LinkedList&gt;
  • 是的,好点,这种嵌套擦除很棘手。但是对于 HashMap 我认为这不是问题。仅使用 hashCode() 和 equals() 执行检查...
【解决方案4】:

是的(假设类加载器表现良好,即 ir 在给定相同名称时总是返回相同的 Class 对象。)

Class 实例的hashCode 是它的对象标识(Class 不要重新定义hashcode),它在对象的生命周期内保持不变。 JLS 声明 在其加载器可能可访问时,不得卸载类或接口(为了避免重新加载类,这对应用程序不透明,因为对象标识Class 对象的值会有所不同)。

请注意,同名的类,但由不同的类加载器加载,具有不同的哈希码。通常这应该不是问题,因为它们将是 different run-time types,并且它们的实例不会与分配兼容。

【讨论】:

    猜你喜欢
    • 2016-11-05
    • 1970-01-01
    • 2017-11-09
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    相关资源
    最近更新 更多