Ok, I guess I'll morph this issue a bit. I came to the conclusion that
generics were the way to go, but why should I need to define a
parameter with a class to do what I want to do?
Because that's how Java does it.
I think of the types of variables in an object as implementation
details.. But the following doesn't work:
import java.util.*;
class AA
{
Set<?> example;
aa()
The constructor name must match the class name. This line as shown will not
compile, as it is legal for neither constructor nor method.
Both class and constructor must be public if you wish to use them outside the
package in which they're defined.
{
example = new HashSet<Integer>();
_setHelper(example, new Integer(1));
System.out.println(example);
}
private<K> void _setHelper(Set<K> parm, K key)
Convention has it that one not use underscores in method names.
To your actual point, 'Set<?>' and 'Set<K>' have different meanings. Just
telling the method that the 'Set<?>' is actually a 'Set<Integer>' isn't quite
enough. Generally, with "extends" wildcards (? is shorthand for "? extends
Object"), you cannot safely "put()" (i.e., "add()" in this context).
See these articles:
<
http://java.sun.com/docs/books/tutorial/extra/generics/index.html>
particularly,
<
http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html>
<
http://www.ibm.com/developerworks/java/library/j-jtp04298.html>
<
http://www.ibm.com/developerworks/java/library/j-jtp07018.html>
The compiler errors will indicate what you did wrong, but in more general
terms, you aren't locking down your type analysis with this kind of thing. If
'example' is meant to be a 'Set<Integer>', it should be declared as such. If
the whole class is meant to be a general handler for different types of sets,
where the instance will deal throughout with the same type, then the class
itself should have the type parameter. Also, there's little point in passing
a member variable as an argument to a member method of the same class. It
already has access to the member variable.
{
parm.add(key);
}
}
where I'm attempting to give the compiler a little push in the right
direction, showing that Set<K> should be linked with the ?. I would
have thought this would have worked, but no.
That's because you are misusing the generics syntax. The right way to do this
is to have the <K> in the 'Set' declaration itself. You were trying to tell
the compiler that 'Set' can have literally any type of object in it with the
<?>, and also simultaneously that it can only have 'K' (in this case,
'Integer') in it. You can't get both promises at the same time because they
contradict each other.
Furthermore, <?> means that whatever type 'Set' contains, all its elements are
of that type. If your method were legal, it could be called at different
times with different 'K' types, all trying to 'add()' to the same set. That
wouldn't be legal either.
Of course, if I explicitly cast it - (Set<Integer>)example, it works,
but that gets rid of the point of generics, doesn't it?
It does generate a warning to that effect.
It was the failure to lock down the 'example' type parameter to that of the
method that got rid of that point, actually.
So any ideas around this?
Do it like this:
public class AA
{
Set<Integer> example = new HashSet<Integer>();
public void loadAndPrintln()
{
example.add( Integer.valueOf(1) );
System.out.println( example );
}
}
If you want 'AA' to be generic so that client code can use it for 'Integer',
'String' or whatever, the generic parameter should be on the class itself.
public class AA <K>
{
Set <K> example = new HashSet <K> ();
public void loadAndPrintln( K value )
{
example.add( value );
System.out.println( example );
}
}
That's kind of the point of generics, isn't it?
(ps [sic] - wrt language lawyering, with all respect I detest camelcase, and
will only use it if required by convention. And no - I don't go around
It is "required" by convention. It is not a question of "language lawyering",
as you so disparagingly put it, but of communication. The language itself
lets you do things differently, but that doesn't mean that you should do
things differently. The conventions make life easier in a world where one is
not the only resident.
However, whatever convention you do follow, the constructor name must match
the case of the class name. The compiler will refuse to cooperate if you don't.
naming my variables mySet, etc.. I do it for example.. so thanks for
the concern, but no thanks..
One period suffices to indicate a declarative sentence.