I have recently seen that one can declare a return type that is also bounded by an interface. Consider the following class and interface:
public class Foo {
public String getFoo() { ... }
}
public interface Bar {
public void setBar(String bar);
}
I can declare a return type like this:
public class FooBar {
public static <T extends Foo & Bar> T getFooBar() {
//some implementation that returns a Foo object,
//which is forced to implement Bar
}
}
If I call that method from somewhere, my IDE is telling me that the return type has the method String getFoo() as well as setBar(String), but only If I point a dot behind the Function like this:
FooBar.getFooBar(). // here the IDE is showing the available methods.
Is there a way to get a reference to such an Object? I mean, if I would do something like this:
//bar only has the method setBar(String)
Bar bar = FooBar.getFooBar();
//foo only has the getFoo():String method
Foo foo = FooBar.getFooBar();
I would like to have a reference like this (pseudo code):
<T extents Foo & Bar> fooBar = FooBar.getFooBar();
//or maybe
$1Bar bar = FooBar.getFooBar();
//or else maybe
Foo&Bar bar = FooBar.getFooBar();
Is this possible somehow in Java, or am I only able to declare return types like this? I think Java has to type it also, somehow. I’d prefer not to resort to a wrapper like this, as it feels like cheating:
public class FooBarWrapper<T extends Foo&Bar> extends Foo implements Bar {
public T foobar;
public FooBarWrapper(T val){
foobar = val;
}
@Override
public void setBar(String bar) {
foobar.setBar(bar);
}
@Override
public String getFoo() {
return foobar.getFoo();
}
}
Did Java really invent such a nice feature, but forget that one would like to have a reference to it?
While the type parameters of a generic method can be restricted by bounds, such as
extends Foo & Bar, they are ultimately decided by the caller. When you callgetFooBar(), the call site already knows whatTis being resolved to. Often, these type parameters will be inferred by the compiler, which is why you don’t usually need to specify them, like this:But even when
Tis inferred to beFooAndBar, that’s really whats happening behind the scenes.So, to answer your question, such a syntax like this:
Would never be useful in practice. The reason is that the caller must already know what
Tis. EitherTis some concrete type:Or,
Tis an unresolved type parameter, and we’re in its scope:Another example of that:
Technically, that wraps up the answer. But I’d also like to point out that your example method
getFooBaris inherently unsafe. Remember that the caller decides whatTgets to be, not the method. SincegetFooBardoesn’t take any parameters related toT, and because of type erasure, its only options would be to returnnullor to "lie" by making an unchecked cast, risking heap pollution. A typical workaround would be forgetFooBarto take aClass<T>argument, or else aFooFactory<T>for example.Update
It turns out I was wrong when I asserted that the caller of
getFooBarmust always know whatTis. As @MiserableVariable points out, there are some situations where the type argument of a generic method is inferred to be a wildcard capture, rather than a concrete type or type variable. See his answer for a great example of agetFooBarimplementation that uses a proxy to drive home his point thatTis unknown.As we discussed in the comments, an example using
getFooBarcreated confusion because it takes no arguments to inferTfrom. Certain compilers throw an error on a contextless call togetFooBar()while others are fine with it. I thought that the inconsistent compile errors – along with the fact that callingFooBar.<?>getFooBar()is illegal – validated my point, but these turned out to be red herrings.Based on @MiserableVariable’s answer, I put together an new example that uses a generic method with an argument, to remove the confusion. Assume we have interfaces
FooandBarand an implementationFooBarImpl:We also have a simple container class that wraps an instance of some type implementing
FooandBar. It declares a silly static methodunwrapthat takes aFooBarContainerand returns its referent:Now let’s say we have a wildcard parameterized type of
FooBarContainer:We’re allowed to pass
unknownFooBarContainerintounwrap. This shows my earlier assertion was wrong, because the call site doesn’t know whatTis – only that it is some type within the boundsextends Foo & Bar.As I noted, calling
unwrapwith a wildcard is illegal:I can only guess that this is because wildcard captures can never match each other – the
?argument provided at the call site is ambiguous, with no way of saying that it should specifically match the wildcard in the type ofunknownFooBarContainer.So, here’s the use case for the syntax the OP is asking about. Calling
unwraponunknownFooBarContainerreturns a reference of type? extends Foo & Bar. We can assign that reference toFooorBar, but not both:If for some reason
unwrapwere expensive and we only wanted to call it once, we would be forced to cast:So this is where the hypothetical syntax would come in handy:
This is just one fairly obscure use case. There would be pretty far-ranging implications for allowing such a syntax, both good and bad. It would open up room for abuse where it wasn’t needed, and it’s completely understandable why the language designers didn’t implement such a thing. But I still think it’s interesting to think about.
Note – Since JDK 10 there is the
varreserved type name, which makes this possible:The variable
fooBaris inferred to have a type that implements bothFooandBarand that cannot be denoted explicitly in source code.A note about heap pollution
(Mostly for @MiserableVariable) Here’s a walkthrough of how an unsafe method like
getFooBarcauses heap pollution, and its implications. Given the following interface and implementations:Let’s implement an unsafe method
getFoo, similar togetFooBarbut simplified for this example:Here, when the new
Foo2is cast toT, it is "unchecked", meaning because of type erasure the runtime doesn’t know it should fail, even though it should in this case sinceTwasFoo1. Instead, the heap is "polluted", meaning references are pointing to objects they shouldn’t have been allowed to.The failure happens after the method returns, when the
Foo2instance tries to get assigned to thefoo1reference, which has the reifiable typeFoo1.You’re probably thinking, "Okay so it blew up at the call site instead of the method, big deal." But it can easily get more complicated when more generics are involved. For example:
Now it doesn’t blow up at the call site. It blows up sometime later when the contents of
foo1Listget used. This is how heap pollution gets harder to debug, because the exception stacktrace doesn’t point you to the actual problem.It gets even more complicated when the caller is in generic scope itself. Imagine instead of getting a
List<Foo1>we’re getting aList<T>, putting it in aMap<K, List<T>>and returning it to yet another method. You get the idea I hope.