The problem in general is the Java security model, which is actually trying to prevent the reloading of an already loaded class.
Of course, Java from the very beginning supported dynamic loading of classes, which is difficult - reloading the class.
It was considered harmful (and for good reason) that a running Java application was introduced by a new class with malicious code. For example, java.lang.String hacked an implementation coming from the Internet, instead of creating a line, it deletes some random hile file that calls the length () method.
So, they somehow conceived Java (and I suppose the .NET CLR because it was very "inspired" in the JVM) was to prevent the already loaded class from loading again into the same virtual machine.
They proposed a mechanism to override this "function." Classloaders, but again there were rules for class loaders, they should ask the permission of the "parent" class loader before trying to load a new class, if the parent has already loaded the class, the new class is ignored.
For example, I used class loaders that load classes from LDAP or RDBMS
Hot deployment becomes a necessity in the Java world when the application server becomes the core for Java EE (and also creates the need for micro-containers such as spring to avoid this kind of burden).
Restarting the entire application server after each compiler causes anyone to be crazy.
So, application server provider, offer this βcustomβ class loader to help with a hot deployment and using the configuration file, this behavior MUST be disabled during installation during production. But the trade-off is that you have to use tons of memory during the development process. Thus, a good way to do this is to restart every 3 to 4 deployments.
This does not happen with other languages ββthat were designed from the very beginning to load their classes.
In Ruby, for example, you can even add methods to a running class, override a method at runtime, or even add a single method to a unique, specific object.
The trade-off in such environments is, of course, memory and speed.
Hope this helps.
EDIT
I found this product some time ago that promises that rebooting makes it as simple as possible. I do not remember the link when I first wrote this answer, and I do it.
This is JavaRebel from ZeroTurnaround