This. The reason for this is that DeferredRegister relies on static initializers. If you put your RegistryObjects in some random class it is not guaranteed that that class is actually initialized by the time your DeferredRegister is. Hence: Put the DeferredRegister and its entries in the same class.
@ObjectHolder is explained here: https://mcforge.readthedocs.io/en/latest/concepts/registries/#using-objectholder
Okay, thanks for the help! A few questions.
BLOCKS and ITEMS are in the same class as each other- it's called 'registry'. (forgot to capitalize, oops- I'll fix that momentarily.) What exactly shouldn't be in separate classes? Are you saying that my actual RegistryObjects (the individual blocks, items, etc.) should all be in the same class? Or that the DeferredRegisters should all be in the same class? Or that all the RegistryObject<Block>s should be in the same class as the DeferredRegister<Block>, and the RegistryObject<Item>s should be in the same class as the DeferredRegister<Item>, but those two classes don't necessarily have to be the same?
What is @ObjectHolder, what does it do, and where can I go to learn more? (That is, assuming it's a Forge thing. If it's a Java thing I don't know, say so and I'll go research it elsewhere- I understand and respect that this forum isn't a place to look for Java help.)
First of all the BLOCKS and ITEMS fields (i.e. your DeferredRegister instances) should not be in a separate class. Put them in the same class or you will have issues.
No, you cannot, because then you defeat the entire purpose of DeferredRegister. You must create your registry objects (blocks, items, etc.) in the registry event. DeferredRegister manages this for you. If you don't want this, you can also manually subscribe to RegistryEvent and create and register your things there. You can then use @ObjectHolder to obtain the instances for your registry entries. You can also mix and match these if you so choose - you can have @ObjectHolder annotated fields and things registered by DeferredRegister will still end up there and equally you can register things manually in RegistryEvent and create your own RegistryObject (just call the of method) which you can then use to access them. But what you cannot do is create registry objects (i.e. blocks and items) outside registry events.
From my understanding, all of my blocks, items, and whatnot should be registered like this:
public static final RegistryObject<Block> CRASH_PAD = registry.BLOCKS.register("crash_pad", () -> new CrashPadBlock(AbstractBlock.Properties.of(Material.CLAY, MaterialColor.GRASS).friction(0.8F).sound(SoundType.SLIME_BLOCK).noOcclusion()));
public static final RegistryObject<Item> ALCHEMICAL_FLASK = registry.ITEMS.register("alchemical_flask", () -> new Item(new Item.Properties().tab(ItemGroup.TAB_MATERIALS)));
If I then wished to refer to the crash_pad Block, or the alchemical_flask Item, do I have to refer to them as 'registry.CRASH_PAD.get()' and 'registry.ALCHEMICAL_FLASK.get()'? This seems a bit roundabout. Can I define the blocks as Blocks and the items as Items before creating and registering RegistryObject<T>s from them, or do I have to always get the blocks and items from their RegistryObjects?