I have a problem with a simple piece of Java code. I cannot determine if it solves the original purpose; the guy that wrote it (yet unreachable) just told me that "an object that implements IA
should be a container ( List
) of IB
-like objects”. At first sight I have considered it wrong, because of the strong constraint ( T extends IB<T>
) seems illogical, but the IDE compiler does not show any related error/warning.
If such code is meaningful, could someone please provide an example of practical usage of such interfaces.
Thanks in advance.
import java.util.List;
public interface IA<T extends IB<T>> {
public List<T> getList();
}
public interface IB<T> {
public T getValue();
}
UPDATE 1 : added test with concrete sample classes
class Bar implements IA<Foo>{
List<Foo> list;
@Override
public List<Foo> getList() {
return list;
}
Bar(List<Foo> foos) {
this.list = foos;
}
}
class Foo implements IB<Foo> {
public Float data;
@Override
public Foo getValue() {
return foo;
}
Foo(Float data){
this.data = data;
}
public Float getV() {
return data;
}
}
public class DataTest {
@Test
public void myTest() {
Foo f = new Foo(10F);
List<Foo> fs = new ArrayList<>();
fs.add(f);
Bar bar = new Bar(fs);
List<Foo> foos = bar.getList();
System.out.println(foos.get(0).getV());
}
}
Is this the correct way to use IA and IB?
As T
is only used in covariant position, it is safe to use as it is, so the comment on IA
can be correct. If IA
had a method accepting a T
(like int compare(T a, T b)
) in one of its parameters, that would cause problems as it were in a contravariant position.
Such a constraint makes sense in certain circumstances. For example, if you want to make an sorted list class, you might do something like
class SortedList<T extends Comparable<? super T>>
where you require that the element type can be compared to itself, which is necessary for you to sort it. (Note that Comparable
itself doesn't have a bound on its type parameter, just like here.)
The super
in the thing above is because Comparable
is a consumer with respect to T
, and so per PECS, you should use super
wildcards with Comparable
. In your case, since IB
is a producer with respect to T
, you could make it public interface IA<T extends IB<? extends T>>
public interface IA<T extends IB<? extends T>>
if you want to make it most general.
As to an actual use case that uses this constraint, here's one I came up with that is a class that uses the constraint:
class Bar<T extends IB<T>> implements IA<T> {
T start;
@Override
public List<T> getList() {
List<T> result = new ArrayList<T>();
for (T x = start; x; x = x.getValue()) {
result.add(x);
}
return result;
}
Bar(T start) {
this.start = start;
}
}
Where you have an implementing class that it itself generic (with the same <T extends IB<T>>
bound), and it takes one T
and generates more T
s until it reaches null
, and returns a list of these.
Though this still doesn't require that the interface IA
have the constraint, so I guess it still doesn't provide an example where the bound on the parameter of IA
is necessary.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.