One funny/annoying part of implementing a Java runtime is that you want mostly coherent handling of basic classes like Object, Class, String,etc.. (don't want tons of special cases in a JIT,etc) but the reflection data that defines Object and Class contains String's (That inherits from Object for a fun circular dependency).
For the most complete runtime I did (supported basic reflection,etc) I went with faux-object's,strings,etc when starting up created from C definitions that mirrored the real object shapes and then once far into loading walked the heap to modify the faux-objects to point the vtables to the actually loaded types for those classes.
See here: https://github.com/oracle/graal/tree/master/substratevm/src