Java Generics - Difficulty Providing Strong Type Checking
Here's my code:
public class Sequence<T> {
protected List<T> sequence = new ArrayList<T>();
public Matrix<OrderedPair<T, ?>> createCartesianProduct(Sequence<?> secondSequence) {
Matrix<OrderedPair<T, ?>> result = new Matrix<OrderedPair<T, ?>>();
for (int rowIndex = 0; rowIndex < sequence.size(); rowIndex++) {
Sequence<OrderedPair<T, ?>> row = new Sequence<OrderedPair<T, ?>>();
for (int columnIndex = 0; columnIndex < secondSequence.length(); columnIndex++) {
row.add(new OrderedPair(sequence.get(rowIndex), secondSequence.sequence.get(columnIndex)));
}
}
return result;
}
}
This compiles in Eclipse, but on the line inside the for (row.add (...)) loop, I get the following three warnings:
-
OrderedPair
is the raw type. Generic type referencesOrderedPair()<T1, T2>
must be parameterized. - Type Safety: An expression of type OrderedPair requires a raw conversion to match
OrderedPair<T, ?>
- Security type: The constructor OrderedPair (Object, Object) is of the raw OrderedPair type. References to the generic OrderedPair type
<T1, T2>
must be parameterized
I would like to use generics to force type checking here, but I think my understanding of generics is not enough for me to see how to do it. Can anyone enlighten me?
Thank,
- Ken
The constructor in the inner for loop must have generics:
row.add(new OrderedPair <T, ?> (sequence.get(rowIndex), secondSequence.sequence.get(columnIndex)));
But you cannot use ?
like this; so you will need to replace everything ?
with a letter for example E
. Then add <E>
to the signature, for example:
public <E> Matrix<OrderedPair<T, E>> createCartesianProduct(Sequence<E> secondSequence) {
Otherwise, the compiler doesn't know where it came from E
.
source to share
The OrderedPair is not generated, but is added to the Sequence that is generated. You have to build an OrderedPair with generics for example. do "new OrderedPair <...> (...)" to get rid of this warning.
Here I added generics for the whole method, so the return type matches the type of secondSequence:
public <Z> Matrix<OrderedPair<T, Z>> createCartesianProduct(Sequence<Z> secondSequence) {
Matrix<OrderedPair<T, Z>> result = new Matrix<OrderedPair<T, Z>>();
for (int rowIndex = 0; rowIndex < sequence.size(); rowIndex++) {
Sequence<OrderedPair<T, Z>> row = new Sequence<OrderedPair<T, Z>>();
for (int columnIndex = 0; columnIndex < secondSequence.length(); columnIndex++) {
addToRow(row, sequence.get(rowIndex), secondSequence.sequence.get(columnIndex));
}
}
return result;
}
static <T, Z> void addToRow(Sequence<OrderedPair<T, Z>> seq, T t, Z z) {
seq.add(new OrderedPair<T, Z>(t, z));
}
source to share
I think you are a little confused here. Sequence<T>
Will the type be T
?
If you define a Sequence<OrderedPair<T, ?>>
, then you end up with recursion on T.
See what you really need:
public class Sequence<T> {
protected List<T> sequence = new ArrayList<T>();
public <T2> Matrix<OrderedPair<T, T2>> createCartesianProduct(Sequence<T2> secondSequence) {
Matrix<OrderedPair<T, T2>> result = new Matrix<OrderedPair<T, T2>>();
for (int rowIndex = 0; rowIndex < sequence.size(); rowIndex++) {
Sequence<T> row = new Sequence<T>();
for (int columnIndex = 0; columnIndex < secondSequence.length(); columnIndex++) {
row.add(new OrderedPair<T, T2>(sequence.get(rowIndex), secondSequence.sequence.get(columnIndex)));
}
}
return result;
}
}
source to share
All you have to do is add a generic type to your constructor, for example:
row.add(new OrderedPair<T, ?>(sequence.get(rowIndex), secondSequence.sequence.get(columnIndex)));
The compiler is throwing errors because it OrderedPair
expects to receive types <T, ?>
as long as you pass them without any explicit type. unchecked conversion
the compiler is talking about since basically you are providing a constructor <?, ?>
while it wants <T, ?>
, hence the uncontrolled conversion that happens and that can throw an exception if accidentally mistaken.
source to share