public class Main {
interface Foo { }
interface Bar { }
static class FooBarImpl implements Foo, Bar { }
//a simple container class
static class FooBarContainer<T extends Foo & Bar> {
private final T fooBar;
public FooBarContainer(T fooBar) {
this.fooBar = fooBar;
}
public T get() {
return fooBar;
}
//a silly static unwrap method
static <T extends Foo & Bar> T unwrap(FooBarContainer<T> fooBarContainer) {
return fooBarContainer.get();
}
}
public static void main
(String[] args
) {
// concrete parameterized type
FooBarContainer<FooBarImpl> fooBarContainer = new FooBarContainer<FooBarImpl>(new FooBarImpl());
// wildcard parameterized type
FooBarContainer<?> unknownFooBarContainer = fooBarContainer;
// passing in a concrete parameterized type
FooBarContainer.<FooBarImpl>unwrap(fooBarContainer); // T is specified to be FooBarImpl
FooBarContainer.unwrap(fooBarContainer); // T is inferred to be FooBarImpl
// passing in a wildcard parameterized type
FooBarContainer.<?>unwrap(unknownFooBarContainer); // T is specified to be ? - compiler error
FooBarContainer.unwrap(unknownFooBarContainer); // T is inferred to be ? - legal (!)
// unwrapping unknownFooBarContainer returns a reference of type ? extends Foo & Bar
// we can assign to Foo or Bar, but not both
Foo foo = FooBarContainer.unwrap(unknownFooBarContainer);
Bar bar = FooBarContainer.unwrap(unknownFooBarContainer);
// if unwrap were expensive, we would be forced to cast
Foo foo2 = FooBarContainer.unwrap(unknownFooBarContainer);
Bar bar2 = (Bar)foo2;
// so this is where the hypothetical syntax would come in handy
Foo&Bar fooBar = FooBarContainer.unwrap(unknownFooBarContainer);
}
}