Let's look at your method declaration:
private static ArrayList<HeavenlyBody> makingSetOfMoons(){
Java expects the method to return an ArrayList<HeavenlyBody>
But you return the moons variable which is declared:
List<HeavenlyBody> moons = ....
It doesn't matter what type of List subtype that you assign to the variable -- Java sees the variable as a List<HeavenlyBody>
, pure and simple. Even if you assign an ArrayList<HeavenlyBody>
to this variable, the Java compiler cannot use this to do an automatic implicit cast for you, because you could later in the method change the object that the variable refers to, now or later, and this could cause problems. As Jon Skeet states here:
The compiler uses the declared type of the variable to know how it can be used... it's as simple as that.
One solution is to change the moons variable to:
ArrayList<HeavenlyBody> moons = ...
This would work but would be wrong since it is almost always better to "code to the interface" (see: What does it mean to “program to an interface”?). Better to change the return type expected by the method in its declaration:
private static List<HeavenlyBody> makingSetOfMoons() {
This all gets down to the difference between a reference variable and a reference (or object), specifically the type of each. It is a fine distinction but an important one.
The variable and its type:
List<HeavenlyBody> moons
This variable is a reference variable that refers to an object, as opposed to a primitive variable that refers to a primitive type.
Currently you assign this reference to the variable:
new ArrayList<>();
and so the type of the variable is List<HeavenlyBody>
and the type of the reference that it refers to is ArrayList<HeavenlyBody>