M
Murat Tasan
disclaimer: i already know about type erasure, so i understand the logical
flaw present here. what i'm most interested in is knowing:
a) why i don't get a compiler error (i think i should, but i don't, not
even a warning with all flags turned on).
b) how others have gotten around this eloquently (i.e. without a ton of
unchecked warnings)
okay, here are 4 very small classes than can be used to test this. first,
i have a DistanceFunction interface with one method:
public interface DistanceFunction<D extends Number & Comparable<D>>
{
public D computeDistance(Object o1, Object o2);
}
and i have an implementing class of this interface:
public class TestDistanceFunction implements DistanceFunction<Double>
{
public Double computeDistance(Object o1, Object o2)
{
return 69.0d;
}
}
and i have another class that should be initialized by using the output of
a distance function:
public class TestContainer
{
public <D extends Number & Comparable<D>> TestContainer(D c)
{
}
}
now. when i compile all of this, everything is kosher. in particular, i
think the constructor of TestContainer should at least give me a warning.
why? because when type erasure occurs for types using multiple
inheritance (i.e. <D extends Number & Comparable<D>>), the FIRST
class/interface listed is the chosen erasure class.
this implies that i cannot have a reference to an object with the
reference having more than one type. (i.e. i cannot have a true multiple
inheritance reference).
thus, i should NEVER be able to pass a correct D to TestContainer(D c).
nevertheless, the compiler thinks everything is fine, which is misleading.
it turns out that my intuition is correct and i CANNOT ever seem to create
a new TestContainer.
note the final test class:
public class Test
{
public static void main(String[] args)
{
DistanceFunction<?> d = new TestDistanceFunction();
Number x = d.computeDistance(null, null);
Comparable<? extends Number> y = d.computeDistance(null, null);
// TestContainer container = new TestContainer(x);
// TestContainer container = new TestContainer(y);
// TestContainer container = new TestContainer(d.computeDistance(null,
null));
}
}
un-commenting any of the commented lines causes failure. why? because no
appropriate constructor signature of TestContainer is found.
i expect the error certainly when calling with x and y. but even the last
attempt fails.
now, once again. i understand why it fails. i do not understand why when
compiling TestContainer i don't receive either an error or a warning about
this.
second part of the question (although i'm far more interested in the
first part, i unfortunately also have work to do...). the above
illustrates that i want to make a TestContainer that can hold results of
some distance function. but i want all results to be of the same
Comparable type, to get rid of catching ClassCastExceptions when sorting a
group of results. nevertheless, i would like to keep references to the
results as Number, as i will never explicitly call compareTo(), the sort()
methods will do that.
i know i can cast my Number references to the raw type Comparable, but
then i get either ugly unchecked warnings or i have to worry about
ClassCastExceptions. both of these i'd like to avoid using generics.
(isn't that part of the point of generics in java?)
anyone have a similar problem with multiple inheritance and have an
eloquent solution using generics?
thanks much.
flaw present here. what i'm most interested in is knowing:
a) why i don't get a compiler error (i think i should, but i don't, not
even a warning with all flags turned on).
b) how others have gotten around this eloquently (i.e. without a ton of
unchecked warnings)
okay, here are 4 very small classes than can be used to test this. first,
i have a DistanceFunction interface with one method:
public interface DistanceFunction<D extends Number & Comparable<D>>
{
public D computeDistance(Object o1, Object o2);
}
and i have an implementing class of this interface:
public class TestDistanceFunction implements DistanceFunction<Double>
{
public Double computeDistance(Object o1, Object o2)
{
return 69.0d;
}
}
and i have another class that should be initialized by using the output of
a distance function:
public class TestContainer
{
public <D extends Number & Comparable<D>> TestContainer(D c)
{
}
}
now. when i compile all of this, everything is kosher. in particular, i
think the constructor of TestContainer should at least give me a warning.
why? because when type erasure occurs for types using multiple
inheritance (i.e. <D extends Number & Comparable<D>>), the FIRST
class/interface listed is the chosen erasure class.
this implies that i cannot have a reference to an object with the
reference having more than one type. (i.e. i cannot have a true multiple
inheritance reference).
thus, i should NEVER be able to pass a correct D to TestContainer(D c).
nevertheless, the compiler thinks everything is fine, which is misleading.
it turns out that my intuition is correct and i CANNOT ever seem to create
a new TestContainer.
note the final test class:
public class Test
{
public static void main(String[] args)
{
DistanceFunction<?> d = new TestDistanceFunction();
Number x = d.computeDistance(null, null);
Comparable<? extends Number> y = d.computeDistance(null, null);
// TestContainer container = new TestContainer(x);
// TestContainer container = new TestContainer(y);
// TestContainer container = new TestContainer(d.computeDistance(null,
null));
}
}
un-commenting any of the commented lines causes failure. why? because no
appropriate constructor signature of TestContainer is found.
i expect the error certainly when calling with x and y. but even the last
attempt fails.
now, once again. i understand why it fails. i do not understand why when
compiling TestContainer i don't receive either an error or a warning about
this.
second part of the question (although i'm far more interested in the
first part, i unfortunately also have work to do...). the above
illustrates that i want to make a TestContainer that can hold results of
some distance function. but i want all results to be of the same
Comparable type, to get rid of catching ClassCastExceptions when sorting a
group of results. nevertheless, i would like to keep references to the
results as Number, as i will never explicitly call compareTo(), the sort()
methods will do that.
i know i can cast my Number references to the raw type Comparable, but
then i get either ugly unchecked warnings or i have to worry about
ClassCastExceptions. both of these i'd like to avoid using generics.
(isn't that part of the point of generics in java?)
anyone have a similar problem with multiple inheritance and have an
eloquent solution using generics?
thanks much.