Why does the declaration
Set<Set<String>> var = new HashSet<Set<String>>();
work but the declaration
Set<Set<String>> var = new HashSet<HashSet<String>>();
choke?
I’m aware that ‘top level’ (not sure if that’s the correct phrase here) generics in a declaration play by different rules than those inside the pointy brackets, but I’m interested to learn the reason. Not an easy question to google, so I thought I’d try you guys.
It’s because you could circumvent the type system if it were allowed. The property you desire is called covariance. If collections were covariant then you’d be able to do this:
A TreeSet is a type of Set, and so static type checking would not prevent you from inserting a TreeSet into var. But var expects HashSets and HashSets only, not any old type of Set.
Personally, I always write your first declaration:
The outer class needs to have a conrete implementation, but there’s usually no need to nail down the inner class to HashSet specifically. If you create a HashSet of Sets you are good to go. Whether you then proceed to insert a series of HashSets into var is your choice later in the program, but no need to restrict the declaration.
For what it’s worth, arrays in Java are covariant, unlike the collection classes. This code will compile and will throw a runtime exception instead of being caught at compile time.