When the classloader encounters the anonymous class Object() {...} , it loads it under the name TestClass$1 . This creates a conflict with class TestClass$1 {...} , which was explicitly defined.
However, class name conflicts are handled fairly shamelessly. This bit of documentation tells us that
If class c is already bound, then this method simply returns.
What happens in your case. You load only one of the two TestClass$1 classes.
The "names of different variables" are not responsible for anything other than re-compiling and re-linking inside your compiler. At this point, the class loader can choose which of the two TestClass$1 better and use it everywhere.
If you use something like eclipse (like me), your bytecode will be cached until a new touch operation in the source file (and timestamp updates ...). Here is what I did to reproduce (running openjdk 1.7, Eclipse Kepler under RedHat):
Put this in the source file TestClass.java :
package javaclasses.classes; public class TestClass{ public static void main(String...args){ Object o = new Object (){ public String toString() { return "hello"; } }; TestClass$1 test = new TestClass$1(); System.out.println(o.toString()); test.doStuff(); } } class TestClass$1{ public void doStuff(){ System.out.println("hello2"); } }
ctrl + F11 outputs:
javaclasses.classes.TestClass$1@42293b53 hello2
Open it in the console and touch TestClass.java
Go back to eclipse and ctrl + F11 now displays:
hello Exception in thread "main" java.lang.NoSuchMethodError: javaclasses.classes.TestClass$1.doStuff()V at javaclasses.classes.TestClass.main(TestClass.java:13)
Inclusion: all that can be said definitively is that the ClassLoader class is by default unreliable for manually resolving classes with the same full names. Changing variable names does not matter, updated timestamp in source file.