1

I have been lurking the net for a while now, but haven't found an answer to this yet. Someone is mentioning Class<T> as key here on SO (I think) but I can't find the post anymore. In any case, this question deserves a proper answer (apologizing if there is a thousand post thread on it).

Is Class<T> immutable? Can it be safely and efficiently used as key (constant hashCode() over execution) ?

My guess would be yes, because the Class definition doesn't change at runtime. But I am not quite sure...thank you!

EDIT: talking about Java.

Andrea Richiardi
  • 703
  • 6
  • 21

4 Answers4

2

An immutable object in Java is one that cannot have its internal state changed via any normal (non-reflective) execution paths. This means that:

  • The class defines no accessible methods that mutates its internal state
  • The class is designed in such a way as to prevent sub-classes from mutating its internal state

The Java Class class fulfills these requirements:

  • It provides no methods for mutating its internal state.
  • The class itself is final, and cannot be sub-classed.

The actual class definition of course, is loaded by the JVM via a classloader, and once defined, is set for the lifetime of that JVM and does not change.

Perception
  • 79,279
  • 19
  • 185
  • 195
  • Good, thanks. I went on Grep Code and checked the openjdk implementation. There are three static fields there. I don't seem to see hashCode() implementation though. There also is some native call. – Andrea Richiardi Feb 21 '13 at 03:40
  • Taking into consideration @Evgeniy Dorofeev's answer below, I will accept this one, just because it answers explicitly. Thanks both. – Andrea Richiardi Mar 06 '13 at 04:46
2

1) I am not sure if it can be called immutable, at least in the classical sense, take a look

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

2) we can use it in HashMap, Class is a singleton and its hashCode and equals are based on its identity, with a caveat that a class will have different instances in different classloaders, so MyClass.class from classloader1 != MyClass.class from classloader2

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • Can we safely assume that these methods are not called randomly at runtime but just at class loading? Probably yes... – Andrea Richiardi Mar 06 '13 at 03:51
  • 1
    These methods are package private, theres no API for them and we cannot make assumptions on how they behave. Still Class is 100% safe in hash-based collections, it's final and inherits hashCode / equals from Object – Evgeniy Dorofeev Mar 06 '13 at 04:24
0

The hashCode() method for Class isn't overridden, but the JDK specifies the following about the getClass() method:

public final Class<?> getClass()

Returns the runtime class of this Object. The returned Class object is the object that is locked by static synchronized methods of the represented class.

The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:

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

Hence for any instances T obj, T obj2, obj.getClass() and obj2.getClass() return the same (immutable) Class<T> object.

However, be careful of type erasure: this is not true for a LinkedList<T> l1 or a LinkedList<U> l2, because both will return the type erasure class Class<LinkedList>, not a Class<LinkedList<T>> that is specific for T.

Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
  • Nice. It's just curious because, for my second question (is it a good key for HashMap) I'd better ask if Object is immutable, not Class. Wait...am I right? :S – Andrea Richiardi Feb 21 '13 at 03:57
  • Well, everything is an `Object`. I'm just saying that for some `T a`, `a.getClass()` returns a `Class klazz` that is the same as for any `T b`. However this is not true for a `LinkedList l1` or a `LinkedList l2`, because both will return the type erasure class `Class`. – Andrew Mao Feb 21 '13 at 04:19
  • Yes good point, that kind of nested erasure is tricky. But for HashMap I don't think this is a problem. The check is performed using hashCode() and equals() only... – Andrea Richiardi Feb 21 '13 at 04:25
0

Yes (assuming that the class loader is well-beahaved, in the sense that ir always returns the same Class object when given the same name.)

The hashCode of a Class instance is its object identity (Class do not redefine hashcode), which remains constant for the lifetime of the object. The JLS states that one must not unload a class or interface while its loader is potentially reachable (in order to avoid classes to be reloaded, which would not be transparent to the application, because the object identity of the Class object would be different).

Note that classes of the same name, but loaded by different class loaders, have different hash codes. Usually this should not be an issue since they will be different run-time types, and their instances will not be assignment-compatible.

Javier
  • 12,100
  • 5
  • 46
  • 57