Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand the Object.getClass() method?

Tags:

java

The Java Object.getClass() method javadoc says:

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();

Returns: The Class object that represents the runtime class of this object.

What is the runtime class?

What does "returned Class object ... is locked by static synchronized methods" mean?

like image 640
Ryanqy Avatar asked Jun 18 '15 14:06

Ryanqy


2 Answers

getClass gives you the Class instance for the object's actual class at runtime, rather than the type of the reference that you have to it.

A simple example will probably clarify. Say we have a method that accepts anything that implements List and dumps out its class name;

static void foo(List l) {
    System.out.println(l.getClass().getName());
}

We can call it with various different types of lists:

foo(new LinkedList()); // Outputs "java.util.LinkedList"
foo(new ArrayList());  // Outputs "java.util.ArrayList"

Since foo can be called with any List, in the rare (!) situations where it's unavoidable, it can use getClass to figure out the actual class of the instance it's been given.

How to understand returned Class object is locked by static synchronized methods?

static synchronized methods synchronize on the instance of Class that represents the loaded class at runtime, so that calls to such methods can't overlap. Say I have a class, Foo, with a static method notThreadSafe, and I have two threads that need to call it:

// On thread 1
Foo.notThreadSafe();

// On thread 2
Foo.notThreadSafe();

Because it's not thread safe, notThreadSafe would be declared synchronized:

public static synchronized void notThreadSafe() { 
    /* ... */
}

Which is effectively the same as

public static void notThreadSafe() { 
    synchronized (Foo.class) {
        /* ... */
    }
}

(Foo.class is the Class instance for the loaded Foo class.)

So when thread 1 enters the synchronized block, if thread 2 tries to enter that block (or anything else synchronized on Foo.class), it has to wait.

It doesn't have to be two calls to the same method; I could have two static synchronized methods (m1 and m2), where thread 1 is calling m1 and thread 2 is calling m2, and the call to m2 would have to wait for the call to m1 to complete, because they're both synchronizing on the same instance (the Class instance for Foo).

How does this relate to getClass()? Because that same Class instance is what getClass on Foo instances returns:

System.out.println(Foo.class == (new Foo()).getClass()); // true
like image 69
T.J. Crowder Avatar answered Sep 21 '22 11:09

T.J. Crowder


"Runtime class" is the Class object associated with the effective type of the object. It means if you do :

Object o = new String();
System.out.println(o.getClass());

You will get class java.lang.String, because the actual, runtime class of o is String. You can't predict this at compile time.

As for the "locked by synchronized static methods", it really means that, for a method declared inside class ThisClass :

public static synchronized foo() {
    ...
}

... is equivalent to :

public static foo() {
    synchronized(ThisClass.class) {
        ...
    }
}

That is, the Class object is used as the lock for all synchronized static methods. More on synchronized blocks and locks here.

like image 34
ttzn Avatar answered Sep 18 '22 11:09

ttzn