ClassLoader.loadClass or Class.forName seem to be synonyms for the same basic operation: request a dynamic class load. Yet calling Class.forName does additional "checking" which is not very useful (certainly in OSGi).
When doing a dynamic class load, the returned type has no implied type by the code. The code must use reflection to access static members or to create an instance. A created instance can either be reflected upon or cast to a type which must already implicitly know by the code. This cast will result in a runtime type check which will ensure type safety.
This is very different than an implicit class load done by the VM to resolve a class constant pool entry. Since it is the goal of these implicit class loads to avoid runtime type checks, the loader constraints are used to ensure type safety.
It does not seem necessary or reasonable to impose loader constraint checks on some dynamic class load requests. That is, code calling Class.forName (or ClassLoader.loadClass) and the VM resolving a class constant pool entry have different type safety needs. The former does not require loader constraint checks since that will be done at runtime by a type cast if needed. The latter does require loader constraint checks to avoid the need for runtime type checks.
So it does seem reasonable to have Class.forName behavior altered to avoid loader constraint checks. Only internal VM class load requests need to check loader constraints.