From your example,
static void showDogs2( Set<? extends Dog> dogs )
Is the correct solution. This is exactly what wildcards were designed
for. You should learn the acronym that Joshua Bloch invented as a
mnemonic: PECS - Producer Extends, Consumer Super.
In this case, showDogs2 is a producer in the sense that within the
method body, the variable "dogs" produces dogs for output, but the
method body doesn't put any dogs into the set, or modify the set in anyway.
This
Set<? extends Dog> someDogs2 = someDalmatians;
Is wrong, in the sense that it's too hamstrung to be useful. As your
comments indicate, it's hard to work with, and doesn't really do what
you want either. As a corollary, this
static Set<? super Dog> makeSomeDogs() {...
would be broken for the same reason. You almost never want to return a
type with a wildcard. Just give the user an single type, it will do
what you wanted much better than the wildcard version.
static Set<Dog> makeSomeDogs() {...
Finally, where do you use the super wild card then? Something like this:
static void copy(Set<? extends Dog> from, Set<? super Dog> to) {...