Same name, different loader, different class
Both loaders read the very same Widget.class file, yet the JVM sees three different Widget classes. Core classes still come from the bootstrap loader, so String is shared.
Before a class can run, a class loader finds its bytes, the JVM links it (verify, prepare, resolve) and finally initialises it by running its static initialisers, exactly once and only on first active use. A class's identity at run time is its name *plus* the loader that defined it.
Change the code and press Run (Ctrl+Enter). Try to predict the output first, then break it on purpose and read the error. Your edits are saved and match the lesson page.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write a program that prints the loader names for Main, java.sql.Connection and java.lang.String (print bootstrap when the loader is null).
Demonstrate the holder idiom: print a line from the holder's static initialiser and show that it runs only when get() is first called, and only once.
Show that a static final String constant is inlined but a static final String computed by a method call is not.
Explain it without notes
Walk through what happens between new Order() executing for the first time and the constructor running.
What is parent delegation and why does Java use it?
Why can ClassCastException: com.acme.Order cannot be cast to com.acme.Order happen?
What is the difference between ClassNotFoundException and NoClassDefFoundError?
Expected output
same name: true
same Class object: false
A's Widget == ours: false
A asked again, cached: true
our Widget instanceof A's: false
String via A is the JDK's: true
package-private access: denied (different runtime package)