K
kelvSYC
One thing that I've never been able to get in Java (or most
programming languages for that matter) is stuff like this:
How do you declare a parameter/variable/etc where the variable can be
any object that implements two different interfaces (or extends a
class and implements an interface)? For example, suppose Foo is a
class and Bar and Baz are interfaces. How do I create a function that
takes in an object that implements both Bar and Baz, or extends Foo
and implements Bar? To me, this is entirely reasonable OO
programming. And in Java, I've always resorted to declaring the
parameter as one thing and using reflection to see if it conforms to
the rest (and throwing an IllegalArgumentException if it does not) -
something like
void f(Foo foo) {
Bar bar;
try {
bar = Bar.class.cast(foo);
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
// ... (since foo and bar now refer to the same thing, I use
whichever is appropriate)
}
I'd thought that when it comes to generics, I can't see that a similar
problem would appear, given that you can use multiple type bounds.
However, why is it that something like
List<? extends Foo & Bar> list = new ArrayList<? extends Foo &
Bar>(); // here, Bar is an interface, Foo can be either class or
interface
or
<T extends Foo & Bar> List<T> list = new ArrayList<T>();
Is it because of weird erasure behaviour? Or is it because there is
still no way to do the first thing (the function with parameter as
described above), thus the second thing is illegal? How do I work
around it (short of code duplication)?
Also, some of you may note that I could simply subinterface/subclass
to avoid the issue, and that is actually acceptable in some
scenarios. However, suppose you have
class A extends Foo;
class B extends Foo implements Bar;
class C extends Foo implements Bar, Baz;
class D extends Foo implements Baz
Then List<? extends Foo & Bar> would mean, to me at least, a
homogeneous container (containing Bs and Cs, but not As). Still, it
would avoid a lot of code duplication (for example, f() would have to
be rewritten to take a B and a C, and possibly anything you make later
matching the conditions)...
programming languages for that matter) is stuff like this:
How do you declare a parameter/variable/etc where the variable can be
any object that implements two different interfaces (or extends a
class and implements an interface)? For example, suppose Foo is a
class and Bar and Baz are interfaces. How do I create a function that
takes in an object that implements both Bar and Baz, or extends Foo
and implements Bar? To me, this is entirely reasonable OO
programming. And in Java, I've always resorted to declaring the
parameter as one thing and using reflection to see if it conforms to
the rest (and throwing an IllegalArgumentException if it does not) -
something like
void f(Foo foo) {
Bar bar;
try {
bar = Bar.class.cast(foo);
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
// ... (since foo and bar now refer to the same thing, I use
whichever is appropriate)
}
I'd thought that when it comes to generics, I can't see that a similar
problem would appear, given that you can use multiple type bounds.
However, why is it that something like
List<? extends Foo & Bar> list = new ArrayList<? extends Foo &
Bar>(); // here, Bar is an interface, Foo can be either class or
interface
or
<T extends Foo & Bar> List<T> list = new ArrayList<T>();
Is it because of weird erasure behaviour? Or is it because there is
still no way to do the first thing (the function with parameter as
described above), thus the second thing is illegal? How do I work
around it (short of code duplication)?
Also, some of you may note that I could simply subinterface/subclass
to avoid the issue, and that is actually acceptable in some
scenarios. However, suppose you have
class A extends Foo;
class B extends Foo implements Bar;
class C extends Foo implements Bar, Baz;
class D extends Foo implements Baz
Then List<? extends Foo & Bar> would mean, to me at least, a
homogeneous container (containing Bs and Cs, but not As). Still, it
would avoid a lot of code duplication (for example, f() would have to
be rewritten to take a B and a C, and possibly anything you make later
matching the conditions)...