Your statement is almost correct. The complete truth is that Class objects are unique within a single ClassLoader. For many standard Java applications, that means Class objects are unique. If you create your own ClassLoaders, or if your code is in an environment (app server, IDE, or other complex framework) which creates multiple ClassLoaders, then it's possible for a given class to be represented more than once. But even in those cases, it's quite difficult to observe the problem.
Note that for each Class object, there's also a searate set of static variables for that class.
But as you explained the situations of having multiple class objects.How can we make sure that synchronization on class level won't be breached.?
Let's say two different threads are requesting for class level locks in a code which is running in an App server. Do we have chances of breaking synchronization rules if both happen to get two different class objects on lock request?
Well, there's where it gets strange. Let's say you have a single class file. Two different ClassLoaders both load it, and each creates a Class object. Furthermore, let's create two instances, one from each of the two Class objects.
Technically, the identity of a class in the Java language includes the ClassLoader that loaded it. That means that the two instances mentioned above actually belong to two separate classes. Each class loader creates its own little universe, and code in classes loaded by each class loader is distinct.
So to make this concrete: let's say your class is named "C", and we'll call the two class loaders '1" and "2". Imagine further that there's a class X loaded by "1" (which we could call X(1)). Code in X(1) has a reference "r" to an object of type C(2) -- i.e., an instance of C loaded in "2". Now, if X(1) executes this statement
System.out.println(r instanceof C);
It will print "false". The two different classes named C are completely separate classes, even though they come from the same class file. Each one has its own static variables, etc.
So yes, each one will have its own static lock, and static synchronized methods in C(1) and C(2) can run simultaneously. If you're using static synchronized methods to protect some external resource -- a file, for example -- then the protection will break. Otherwise, it probably just won't matter, since each class has its own static data, and code in the two class loaders generally won't be trading C objects anyway.
Note that in general, letting a complex environment load a class in more than one class loader is a mistake. You can almost always avoid it by being careful where you install your various jar files and libraries. Things that will be used in multiple class loaders should be placed into the server common area so they are loaded just once by a root class loader. The details, of course, vary by environment.
This is an interesting topic and one that a lot of people are completely unaware of. I'm glad you brought it up.
Will this call not try to load class C using current loader (if not already loaded) and create an object for it? How can I force that class C, loaded by loader2 should be used?
When using the new operator, only the classloaders in the current hierarchy will be searched. So, if you are using classloader CL2 whose parent is CL1 and the above code is executed from a class with the classloader as CL2, then both CL2 and CL1 will be searched for the class definition (Although if the class definition is available with CL1, CL2 will not be searched.). The order of searching(delegation model) is top down i.e. from the parent to the child. However, if you want to explicitly use a classloader which will not be used according to the above rules, then you can use reflection(Class.forName()) to explicitly use a classloader instance.
It's not so much creating the objects you have to worry about, but rather receiving them as method arguments, or getting them from calling methods. Imagine a global service that cached user-provided objects, like a Thread pool, for example. Two different class loaders might load your class C (a task) and add them to the Thread Pool. Then code under either of those loaders could enumerate the tasks in the Thread pool and find instances of the class created by the other loader.
That isn't the clearest example, but I just woke up and it's all I can think of right now