Say I have a class Foo, a class A and some subclass B of A. Foo accepts A and its sublclasses as the generic type. A and B both require a Foo instance in their constructor. I want A's Foo to be of type A , and B's Foo to be of type B or a superclass of B. So in effect, So I only want this:
Foo<X> bar = new Foo<X>;
new B(bar);
to be possible if X is either A, B, or a both subclass of A and superclass of B.
So far this is what I have:
class Foo<? extends A>{
//construct
}
class A(Foo<A> bar){
//construct
}
class B(Foo<? super B> bar){
super(bar);
//construct
}
The call to super(...) doesn't work, because <A> is stricter than <? super B>. Is it somehow possible to use the constructor (or avoid code duplication by another means) while enforcing these types?
Edit: Foo keeps a collection of elements of the generic parameter type, and these elements and Foo have a bidirectional link. It should therefore not be possible to link an A to a Foo.
If you change the A constructor to:
class A(Foo<? extends A> bar){
//construct
}
will it do what you want ?
If you really want to limit the constructor of A to Foo then you need to provide another protected method (aka usable from derived classes) to set the Foo instance.
Something like this:
public class A {
Foo<?> foo;
public A(Foo<A> foo) {
setFoo(foo);
}
protected A() {
}
protected void setFoo(Foo<?> foo) {
this.foo = foo;
}
}
and B
public class B extends A {
public B(Foo<? super B> foo) {
setFoo(foo);
}
}
now this works:
new A(new Foo<A>());
new A(new Foo<B>()); // this fails compilation
new B(new Foo<B>());
In order for foo element in A to be properly typed you might need to make A a parametrized class too.
The only way to do this would be to have...
class A(Foo<? extends A> bar) {
//construct
}
But it appears this isn't what you want. You can't have the other approach because when you create an instance of B you are also creating an instance of A (that is part of the B instance). So B can't take in special fields for the parts in A. I'm not sure why you wouldn't allow A's foo to be of type B, could you perhaps expand on that?
The following setup compiled for me:
public interface MarkerInterface {
}
public class A implements MarkerInterface {
public A(Foo<A> fooA) {
}
}
public class SuperB implements MarkerInterface {
}
public class B extends SuperB {
public B(Foo<? super B> fooB) {
}
}
And with the main method:
public static void main(String[] args) {
B b = new B(new Foo<SuperB>());
}
Is this what you're looking for?
Java generics are powerful and well designed; nevertheless we sometimes find them lacking. I don't think there's a good way to do what you want.
The easiest thing to do is to change the declaration of Foo<X> to Foo<X extends A>. If that's not acceptable, you can subclass Foo like this:
class Foo<X> { }
class FooA<X extends A> extends Foo<X> { }
class A {
public A(FooA<? extends A> foo) { }
}
class B extends A {
public B(FooA<? super B> foo) {
super(foo);
}
}
(Note: if you have trouble following, when you see Foo, think ArrayList.)
This has the obvious disadvantage that you have to use FooA rather than Foo, hindering code reuse.
Related
Suppose I have three isolated public classes (no IS-A relationship) A, B and C. I want to define a field in C such that it's type can either be A or B.
Currently I'm achieving this by defining C as below:
class A{} class B{}
public class C<T> {
private T obj;
public C(T param){
if ( !(param instanceof A)
|| !(param instanceof B) ) {
throw new InvalidParameterException("Only types A and B are allowed!");
}
this.obj = param;
}
}
Above code will throw exception only at runtime. But what I would rather prefer is to throw error at compile time itself to generate a compiler error in case any type other than A or B is used to construct C.
Make the constructor private:
private C(T param){
And then provide static factory methods to create instances of particular types:
public static <T extends A> C<T> create(T param) {
return new C<>(param);
}
public static <T extends B> C<T> create(T param) {
return new C<>(param);
}
This doesn't prevent you from using the type C<SomeOtherType>; you just can't create an instance of it.
You could use a marker interface for that:
interface AllowedInC {
// intentionally empty because it will be used as a mere marker
}
class A implements AllowedInC {
...
}
class B implements AllowedInC {
...
}
class C<T extends AllowedInC> {
...
}
Only classes A or B (or another class implementing AllowedInC) will be useable in C<T>.
You can't do that but you can set boundaries on what type you want to accept.
If you have
class A extends BaseType {}
class B extends BaseType {}
you can define the class C to be
class C<T extends BaseType> { ... }
Either a class or an interface as base type work.
I don't know if this is at all possible, but I was thinking of something in Java:
If I have an abstract parent class, I can do this:
public ParentClass add(ParentClass a, ParentClass b);
If ParentClass then has a child and I want to override this method, the child class will still have a ParentClass add(ParentClass, ParentClass) method.
Is there a way to make the parent function derive itself to each child?
I don't know if I'm wording it right, but something like this:
// ParentClass.java
public ParentClass add(ParentClass a, ParentClass b);
// Foo.java
#Override // or an equivalent
public Foo add(Foo a, Foo b) {}
// Bar.java
#Override
public Bar add(Bar a, Bar b) {}
Notice how each child doesn't have a ParentClass add(...) function, but rather one for each of their own types instead?
Obviously I can just make these myself, but I want to be able to create overridable ones in parents. I've never seen this in practice before, so I doubt its existence. I just want to clarify with someone with a higher Java knowledge than me. Thanks.
In theory, which I guess no language has ever done, something like this:
public child add(child a, child b);
// where *child* is the type of the child inheriting the method
In Java covariance of parameters of a method is not allowed.
This inherited method : public ParentClass add(ParentClass a, ParentClass b);
is legal for all children as it will allow to specify any subclass of ParentClass as parameters.
It is more flexible.
Now, if you don't want this flexibility and you want to force a specific type for parameters in the inherited method, you should use a generics abstract class.
public abstract class ParentClass <T extends ParentClass <?>>{
public abstract ParentClass<?> add(T a, T b);
}
And in child class you could write :
public class ChildClass extends ParentClass <ChildClass>{
public ParentClass<?> add(ChildClass a, ChildClass b){
....
}
}
Something like this could work with Generics:
public abstract class ParentClass<T extends ParentClass> {
public abstract T add(T a, T b);
}
class Foo extends ParentClass<Foo> {
#Override
public Foo add(Foo a, Foo b) {
return null;
}
}
class Bar extends ParentClass<Bar> {
#Override
public Bar add(Bar a, Bar b) {
return null;
}
}
No, this question is not about the difference between ? and T; it is about how I turn a < ? > argument into a named < T >.
Consider this example code:
import java.io.Serializable;
class A<T extends Serializable> {
<S extends Serializable> void bar(S arg) { }
void bar2(T arg) { }
}
public class B {
A<? extends Serializable> myA = null;
<T extends Serializable> void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
My problem is the fact that the above doesn't compile; the call to bar2() gives me
The method bar2(capture#2-of ? extends Serializable) in the type
A<capture#2-of ? extends Serializable> is not applicable for the arguments (T)
I guess the "reason" for that is that myA is a < ? extends Serializable >; but the T in B.foo ... is well, a named T; and not the wildcard ?.
One way to "fix" this would be to make < T extends Serializable > a type parameter for class B ... but that basically conflicts with my other usage of that class. Meaning: I ended up writing down B and its member myA like this - exactly because I don't want to parameterize the B class. So, I started with only the bar2() method; and then added bar() later on ... but that doesn't really help either.
So - is there a way to for my class B to use A.bar2() as "intended" in my example code?
EDIT: and just to be precise - the bar() method doesn't help me; as the "S" there ... isn't compatible with the "T" that I am really using in my A class.
You're in a dead end.
A<? extends Serializable> myA = ...;
So myA is a A of something unknown. It could be a A<String>, or a A<Integer> or a A<Banana>. You just don't know. Let's say it's a A<Banana>.
<T extends Serializable> void foo(T arg) {
So foo() accepts any serializable: String, Integer, Banana, Apple, anything. Let's say it's called with an Integer as argument.
myA.bar2(arg);
So, based on the assumptions above, that would call bar2() with an Integer as argument, although myA is a A<Banana>. That can't be accepted by the compiler: it's clearly not type-safe. B must be made generic.
#JBNizet already explains why this can't be done. This answer aims to explain the possible options you have (one of them being rightly pointed out by in your question but that's not the only option).
Make B take a type parameter
class B<T extends Serializable> {
A<T> myA = null;
void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
Make B extend from A (If B passes the is-a test for A)
class B extends A<String> {
public void foo(String arg) {
bar2(arg);
bar(1);
}
}
The difference between the two options is that in 1) both bar and bar2 need to be passed the same type where as in 2) bar and bar2 can be passed different types since bar2 is bound by the type parameter declared for A where as bar is bound by the type parameter declared for the method.
Given any interface I, it is possible to declare a variable that holds a reference to any object of a class C that implements I:
I i = new C();
I want to do something similar. Given two interfaces, I want to declare a variable that holds a reference to any object of a class that implements both interfaces:
interface Foo { void foo(); }
interface Bar { void bar(); }
class Humpty implements Foo, Bar {
public void foo() { System.out.println("Humpty.foo()"); }
public void bar() { System.out.println("Humpty.bar()"); }
}
class Dumpty implements Foo, Bar {
public void foo() { System.out.println("Dumpty.foo()"); }
public void bar() { System.out.println("Dumpty.bar()"); }
}
public class Program {
public static void main(String[] args) {
// I actually have no idea what the syntax should be.
Random random = new Random();
// Fix: I previously used <? extends Foo, Bar>, thanks Jon Skeet and vijucat
<? extends Foo & Bar> foobar;
if (random.nextBoolean())
foobar = new Humpty();
else
foobar = new Dumpty();
foobar.foo();
foobar.bar();
}
}
I have tried the above snippet, but <? extends Foo, Bar> causes a compilation error. What should the correct syntax be? I would like to know if this is possible in other statically typed JVM languages, too: Scala, Kotlin, Ceylon, etc.
If you don't mind suppressing the infamous "Unchecked cast" warning, this is a "solution":
#SuppressWarnings("unchecked")
public class Program {
public static<FooBar extends Foo & Bar> void main(String[] args) {
// Note the explicit cast needed
FooBar foobar = (FooBar) new Humpty();
foobar.foo();
foobar.bar();
// Note the explicit cast needed
foobar = (FooBar) new Dumpty();
foobar.foo();
foobar.bar();
}
}
Also see Jon Skeet's answer, which goes into the circumstances where this is possible elegantly.
Honestly, this should be possible without so many corner cases. The implementation of Java Generics is so messed up that not understanding them probably indicates you know how to allocate your time wisely more than that you are not an expert in a technical area! :-)
Given two interfaces, I want to declare a variable that holds a reference to any object of a class that implements both interfaces
Unfortunately you can't do that. You can do so for a parameter in a generic method, like this:
public static <T extends Foo & Bar> void someMethod(T value) {
Foo x = value;
Bar y = value;
}
... or you could do likewise for an instance variable in a generic class:
class Test<T extends Foo & Bar> {
private T value;
public Test(T value) {
this.value = value;
}
}
... but you can't declare a variable which needs to just satisfy both of those constraints.
(Note the syntax here for two constraints - it's & rather than a comma.)
You could just cast the object. You could do something like this:
Humpty foobar = new Humpty();
((Foo)foobar).foo();
((Bar)foobar).bar();
You can create an interface hierarchy, but that really only applies to related interfaces. This will not work if Bar and Foo are completely unrelated.
interface Foo { void foo(); }
interface Bar extends Foo { void bar(); } //implementations of Bar will need to implement both foo() and bar()
Humpty and Dumpty only need to implement Bar, then you can create an object :
<? extends Foo> foobar = new Humpty();
This is not pretty, but it works, it is safe (modulo null references), and it does not require suppressing any warnings. Jon Skeet was actually headed towards the right direction, but stopped at the middle:
/**
* Existentially quantify over things that implement Foo and Bar.
*
* FooBar = \exists (T extends Foo & Bar). T
*/
interface FooBar extends Foo, Bar {}
/**
* Universally quantify over things that implement Foo and Bar.
*
* \forall (T extends Foo & Bar). T --> WrappedFooBar<T>
* \forall (T extends Foo & Bar). WrappedFooBar<T> --> FooBar
*/
class WrappedFooBar<T extends Foo & Bar> implements FooBar {
private T wrapped;
public WrappedFooBar(T wrapped) { this.wrapped = wrapped; }
public void foo() { this.wrapped.foo(); }
public void bar() { this.wrapped.bar(); }
}
public class Program {
public static void main(String[] args) {
Random random = new Random();
FooBar foobar;
if (random.nextBoolean())
foobar = new WrappedFooBar(new Humpty());
else
foobar = new WrappedFooBar(new Dumpty());
foobar.foo();
foobar.bar();
}
}
The main caveat is that this solution obviously does not scale: one could potentially have to write a huge amount of wrappers.
Is it possible to specify a method which returns a object that implements two or multiple interfaces?
Say we have the following interfaces:
interface FooBar {
[Foo] & [Bar] getFooBar();
}
interface Foo {
void doFoo();
}
inteface Bar {
void doBar();
}
Implementors of FooBar need to provide the method getFooBar() that returns an instance of a type which fullfills Foo as well as Bar.
What I tried so far is to do it with generics:
interface FooBar {
<T extends Foo & Bar> T getFooBar()
}
class SomeImplementor implements FooBar {
private FooAndBarImpl fSomeField;
public <T extends Foo & Bar> T getFooBar() {
return fSomeField;
}
}
Given that FooAndBarImpl is some type provided by a framework or library and implements Foo and Bar this I think should work. However, it doesn't, because "FooAndBarImpl cannot be converted to T". Why is that? The contract implied by getFooBar() is not broken as I see it.
Another solution would be to define a new interface that extends Foo and Bar and to use that as return type. I just don't see much sense in returning a empty wrapper for the fSomeField in the getFooBar() implementation.
EDIT:
Would appreciate it if someone could explain why the generics approach doesn't work. I just don't see it.
You can make T a class parameter:
class SomeImplementor<T extends Foo & Bar> implements FooBar {
private T fSomeField;
public T getFooBar() {
return fSomeField;
}
}
As to why your generics approach didn't work. Lets create the following two classes that implement Foo and Bar:
class A implements Bar, Foo{
private int a;
...
}
class B implements Bar, Foo{
private String b;
...
}
class SomeImplementor implements FooBar {
private A someField;
public <T extends Foo & Bar> T getFooBar() {
return someField;
}
}
So we should now be able to execute the following:
SomeImplementor s = new SomeImplementor();
A a = s.getFooBar();
B b = s.getFooBar();
Although getFooBar() returns an object of type A, which has no valid cast to type B (where will the String member come from?), even though B fulfills the requirement of <T extends Foo & Bar>, i.e. is a valid T.
In short, the compiler (remember, generics is a compile-time mechanism) can't guarantee that every T of type <T extends Foo & Bar> can have an assignment to it of type A. Which is exactly the error you see - the compiler can't convert the given A to every valid T.
Another solution would be to define a new interface that extends Foo and Bar and to use that as return type.
I would say go for this option.
interface FooBar extends Foo, Bar {
FooBar getFooBar();
}
You could return a container to provide Foo and Bar.
public class Container{
private FooBarBam foobar;
public Bar asBar(){
return foobar;
}
public Foo asFoo(){
return foobar;
}
}
This way your code would not have to implement a third interface. Downside is that it is an additional layer of indirection.
As for why the generic approach does not work: there is no way to provide the type of T and the compiler can't just guess its type, so resolving T is not possible.
davin's answer looks good but also requires a public class/interface which implements Foo and Bar to work.
Update:
The problem is that the compiler does not know that the type of T should be FooAndBarImpl, it would have to guess and a guessing compiler leads to bad and unpredictable code.
Even a hack using Lists wont compile since the & operator is not supported. While it should be possible to implement it looks like generics currently don't support multiple bounds within return types.
//Does not compile expecting > after Foo
List<? extends Foo & Bar> getFooBar(){
final List<FooAndBarImpl> l = new ArrayList<FooAndBarImpl>();
l.add(new FooAndBarImpl());
return l;
}