The declaration of asList is : public static <T> List<T> asList(T... a) So when you write : List<Snow> snow2 = Arrays.asList(a); the compiler expects that a is an array of Snow. OK When you give a to asList, the compiler has to find the type of a. With asList(new Light(), new Heavy()); the compiler finds that the "common denominator" for the type is Powder and not Snow ! So it complains. With asList(new Powder(), new Crusty()); the common denominator is ... Snow, so the compiler is happy.
For addAll the declaration is : boolean addAll(Collection<? extends E> c) So, in a List of Snow, you can add any object whose the type extends Snow. Tht's why
List<Snow> snow3 = new ArrayList<Snow>(); Collections.addAll(snow3, new Light(), new Heavy());
I hope it's quite clear and above all that I didn't any mistake.