Irgendwie tue ich mich damit schwer. Evtl. wird das mit der Zeit verständlicher?
Im Prinzip ist das ganz einfach: bei primitiven Datentypen kommt man grundsätzlich ohne new aus, bei komplexen Datentypen braucht man in der Regel ein new, um eine Instanz zu erstellen.
Erklärung:
In Java unterscheiden wir zwischen sog. primitiven Datentypen (boolean, byte, short, int, char, long, float und double) und komplexen Datentypen (auch z. B. Referenztypen genannt) wie Arrays, Klassen, Aufzählungen etc.
Der Unterschied ist, dass bei primitiven Datentypen der Wertebereich und damit auch der Speicherbedarf von vornherein bekannt ist, was bei komplexen Typen nicht der Fall ist (denk z. B. einfach mal an eine Liste, die dynamisch wachsen kann).
Deine Variablen sind Behälter für Werte eines bestimmten Typs. Diese Behälter leben nicht im luftleeren Raum, sondern belegen Platz im Hauptspeicher. Da der Compiler den notwendigen Platzbedarf bei primitiven Typen kennt, kann die Größe des Behälters vom Compiler so gewählt werden, dass ein Wert darin abgelegt werden kann. D. h. eine Variable eines primitiven Typs spieichert unmittelbar den betreffenden Wert.
Bei komplexen Typen geht das nicht, weil Objekte erst während der Ausführung des Programms (sprich: zur Laufzeit) erzeugt werden. Die Größe einer Liste kennt man im Vorfeld eben nicht. Was der Compiler aber weiß ist, wie Groß der Adressraum ist. Er kann also z. B. 32-Bit für das Speichern einer Adresse zur Verfügung stellen und genau das passiert in einer 32-Bit-Umgebung auch: es werden nicht die Objekte selbst sondern nur deren Adressen in den Variablen gespeichert.
Der new-Operator sorgt letztlich dafür, dass ein Objekt zur Laufzeit erzeugt wird, d. h. Speicher für ein Objekt reserviert und dieses Objekt ordentlich initialisiert wird. Das Ergebnis ist dann eben die Adresse des erzeugten Objekts und diese wird dann in der Variablen gespeichert (was problemlos möglich ist, weil der Compiler den Behälter in passender Größe zur Verfügung gestellt hat).
Das ist im Wesentlich schon alles.
Daneben gibt es ein paar Feinheiten: ein String-Objekt kann als Literal angegeben werden, d. h. "X" ist ein String-Objekt, ohne dass man hierfür den new-Operator verwenden hätte müssen (dass das so ist, hat einen tieferen Sinn, den ich an der Stelle nicht näher beschreibe). Ebenso kann ein Array mit einem Objekt initialisiert werden, das ohne new-Operator auskommt. Auch die Werte von Aufzählungen sind Objekte, für die der Programmierer kein new benötigt. Das sind aber Details. Die Grundregel steht oben vor der Erklärung.