The most efficient and at the same time safe way of accomplishing this is as follows:
List<S> supers = List.copyOf( descendants );
The documentation of this function is here: oracle.com - Java SE 19 docs - List.copyOf() The documentation states that this function exists "Since: 10".
The use of this function has the following advantages:
- It is a neat one-liner.
- It produces no warnings.
- It does not require any typecast.
- It does not require the cumbersome
List<? extends S> construct.
- It does not necessarily make a copy !!!
- Most importantly: it does the right thing. (It is safe.)
Why is this the right thing?
If you look at the source code of List.copyOf() you will see that it works as follows:
- If your list was created with
List.of(), then it will do the cast and return it without copying it.
- Otherwise, (e.g. if your list is an
ArrayList(),) it will create a copy and return it.
If your original List<D> is an ArrayList<D>, then in order to obtain a List<S>, a copy of the ArrayList must be made. If a cast was made instead, it would be opening up the possibility of inadvertently adding an S into that List<S>, causing your original ArrayList<D> to contain an S among the Ds, which is a disastrous situation known as Heap Pollution (Wikipedia): attempting to iterate all the Ds in the original ArrayList<D> would throw a ClassCastException.
On the other hand, if your original List<D> has been created using List.of(), then it is unchangeable(*1), so it is okay to simply cast it to List<S>, because nobody can actually add an S among the Ds.
List.copyOf() takes care of this decision logic for you.
(*1) when these lists were first introduced they were called "immutable"; later they realized that it is wrong to call them immutable, because a collection cannot be immutable, since it cannot vouch for the immutability of the elements that it contains; so they changed the documentation to call them "unmodifiable" instead; however, "unmodifiable" already had a meaning before these lists were introduced, and it meant "an unmodifiable to you view of my list which I am still free to mutate as I please, and the mutations will be very visible to you". So, neither immutable or unmodifiable is correct. I like to call them "superficially immutable" in the sense that they are not deeply immutable, but that may ruffle some feathers, so I just called them "unchangeable" as a compromise.