Java interface - Generics - java

I have two interfaces. An interface A, and interface B, which extends interface A. Now, I have class which likes to keep reference of object that either implements A or B. And I would like to provide setter for it. I tried below, but getting type mis match exception.
public interface A {
}
public interface B extends A {
}
public class AB {
private Class<? extends A> object;
public void setObject(Class<? extends A> o){
this.object = o;
}
}
So basically, I would like setObject method to accept an object that either implements interface A or B.

Simple answer:
Type it as A: setObject(A a).
A class that implements B also implements A. Full code:
public class UsesA {
private A a;
public void setObject(A a){
this.a = a;
}
}
Now, if you really want to work with B, you'd type it as B, which would also allow you to treat it as an A, since B inherits from it:
public class UsesB {
private B b; // can call A's methods on this field
public void setObject(B b) {
this.b = b;
}
}
But now you can't pass an A (static) reference to setObject. If you really want to do this, then you'd need to first downcast it as a B, which could fail at runtime. Generics will not improve on this.

If you have an object implementing B, it will also be an instance of A. Because of this, you can make setObject accept any A, which will allow instances of A or B to be passed to it.
public void setObject(A a){
this.object = a;
}

Your code doesn't actually match up with your question. You've stated that
I have class which likes to keep reference of object that either
implements A or B
but the field (called object) is actually a Class, not an Object (instance of a Class).
Your code works if you were truly trying to have your setter accept any interface that extends A. But as you probably realize now from the other answers, you actually want an instance of A :)
public class AB {
private Class<? extends A> type; // renamed from object for clarity
public void setObject(Class<? extends A> type) {
this.type = type;
}
#Test
public void testSetter() {
setObject(A.class); // no errors
setObject(B.class); // no errors
}
}

As suggested earlier if you will use (A a) it will work since B is a type of A. Hence child class can always be represents it's parent.

Related

Composition with different types

I have two Java classes B and C in which both extend from class A (I do not own class A).
public class B extends A {…}
public class C extends A {…}
I need a list of type „ListItem“ to hold instances of either B or C, but since both (B and C) are already extended, they cannot be further extended by using „ListItem“ as a superclass.
I think the only way to go is with composition („has-a“ relation…).
Since „ListItem“ should never have B AND C (but only one of them), I am planning to create ListItem with 2 constructors and set an appropriated
inner type to reflect if either B or C is being hold.
Is there a better approach to accomplish this? Please see the pseudo code below.
public class ListItem {
private enum elemType {
TYPE_B, TYPE_C
}
private final B mBItem;
private final C mCItem;
private final elemType mType;
// used to hold instance of B
public ListItem(B b) {
this.mBItem = b;
this.mType = TYPE_B;
}
// used to hold instance of C
public ListItem(C c) {
this.mCItem = c;
this.mType = TYPE_C;
}
// sample method to demonstrate delegation
private int getAge() {
int age;
if (containsB()) {
age = mBItem.getAge();
}
else if (containsC()) {
age = mCItem.getAge();
}
else {…}
return age;
}
private boolean containsB() {
return (mType == TYPE_B);
}
private boolean containsC() {
return (mType == TYPE_C);
}
}
I mean, you have:
public class B extends A {…}
public class C extends A {…}
So you could just make your item hold an A:
public class ListItem {
private final A item;
public ListItem (A item) {
this.item = item;
}
}
And you have any number of options on how to handle it from there, e.g. simply:
public A getItem () {
return item;
}
And do any appropriate casts or tests from the caller. That's the most flexible way. Or I suppose something like:
public B getB () {
return item instanceof B ? (B)item : null;
}
public C getC () {
return item instanceof C ? (C)item : null;
}
But that's starting to get sloppy, and limits you from storing any other A-derived stuff in your ListItem.
You might want to start questioning your design here. For example, if you're adding some functionality to A that is common to B and C and necessary for the proper operation of a ListItem, consider deriving some class from A to add the common stuff, derive B and C from that, and make your ListItem store that base (of course, if you do this you can't store an A any more):
public class AgedA extends A {
...
public int getAge () { return ... }
}
// Then your B and C both extend AgedA, and your ListItem stores an
// AgedA and can use getAge().
You could make AgedA be abstract and getAge() be virtual, if that's more appropriate. Or you could declare an interface that defines getAge() and use that.
Yet another option is you could (as pointed out in comments) make ListItem be either an interface, or a class that extends A, then have your B and C implement or extend that.
I suppose you could also use generics for ListItem e.g. <? extends A>, although that may not be appropriate especially if your ListItems are mixed. The major benefit of using generics is that e.g. getters can now directly return the subtypes without casts and you give yourself compile-time ability to restrict types to a specific subtype in function parameters and stuff, but otherwise it's essentially the same as just storing an A.
In any case, aside from the advice to just store A in ListItem and handle different types at a higher level, I can't in good conscience give you any other approach suggestions, because the need for all of this seems questionable to me.
I think a clean approach to this is to have your ListItem be an abstract class extending from A, then have B and C extend from ListItem.
Why make ListItem abstract? Any behavior that is shared across B and C can be implemented in the abstract class, and you can additionally impose interfaces requirements on its subclasses.
public abstract class ListItem extends A {
public int getAge () {
// Both B and C share this implementation
}
// But B and C behave differently for this method
public abstract void manipulate ();
}
public class B extends ListItem {
public void manipulate () {
// Something specific to B here.
}
}
public class C extends ListItem {
public void manipulate () {
// Something specific to C here.
}
}
Then you can declare your list of ListItems, insert instances of B and C as necessary, and manipulate them according to the concrete methods or the abstract interface in ListItem:
ArrayList<ListItem> list = new ArrayList<>();
list.add(new B());
list.add(new C());
System.out.println(list.get(0).getAge());
list.get(1).manipulate();
From your description it looks like ListItem is a container for items of type A (B or C, other sub classes in the future). I would recommend using generics, using <? extends A>, you wouldn't then need the more than one constructor and all of A's methods should be available.

Why Does the following code with Cyclic Generics not compile?

Following is my code
class A<B2 extends B, A2 extends A<B2, A2>> {
C<B2, A2> c;
void test() {
c.acceptParameterOfTypeA(this);
}
}
class B {
}
class C<B2 extends B, A2 extends A<B2, A2>> {
void acceptParameterOfTypeA(A2 a) {
}
}
The error occurs at c.acceptParameterOfTypeA(this);.
The error is
The method acceptParameterOfTypeA(A2) in the type C is not
applicable for the arguments (A)
From what I see, the method acceptParameterOfTypeA expects a parameter of type A, and this at the line giving the error is of type A.
What am I doing wrong? How to fix this problem?
If its important, I'm using Java8
I will again rename your classes, so that everything is more readable. So, let's have:
public class First<T extends Second, U extends First<T, U>> {
Third<T, U> c;
void test() {
c.acceptParameterOfTypeA(this);
}
}
class Second {
}
public class Third<X extends Second, Y extends First<X, Y>> {
void acceptParameterOfTypeA(Y a) {
}
}
From the definition of the c member (Third<T, U>), we can conclude that c will expose a method with this signature:
void acceptParameterOfTypeA(U a) { .. }
What is U? U is a sub-type of First<T, U>.
But if U can be substituted with First after type-erasure, this will mean that First extends First<T, First>, which is not true, because U stands for sub-type of First, which is parameterized with some concrete sub-types of Second and First.
In order to get to U, you can apply the so-called Get This approach.
First, since you need U, which is a sub-type of First, but can't get it from First, you can introduce an abstract method that returns it:
abstract class First<T extends Second, U extends First<T, U>> {
Third<T, U> c;
void test() {
c.acceptParameterOfTypeA(getU());
}
abstract U getU();
}
Then, implement a sample sub-class of First, called Fourth, which extends First with some concrete types for T and U, for example:
class Fourth extends First<Second, Fourth> {
Fourth getU() {
return this;
}
}
In the getU() method, just do return this; as this will return the correct substitute for U in the super-class.
More info:
What is the "getThis" trick?
Strategy Pattern with Generics
Simply put, c.acceptParameterOfTypeA() accepts A2. this has type A<B2, A2>, which is not known to extend A2. It's only known that A2 extends A<B2, A2>.
Based on kocko's answer, the original question had the same solution:
public class Main {
abstract class A<A2 extends A<A2, B2>, B2 extends B<A2, B2>> {
B2 b;
void test() {
b.testMethod(getThis()); //getThis() instead of this;
}
abstract A2 getThis();
}
class B<A2 extends A<A2, B2>, B2 extends B<A2, B2>> {
void testMethod(A2 a) {
}
}
public void execute() {
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
We can simplify it by removing the B part which doesn't contribute to the problem -
class A<T extends A<T>>
{
void test(C<T> c)
{
c.acceptParameterOfTypeA(this); // ERROR
}
}
class C<T extends A<T>>
{
void acceptParameterOfTypeA(T a) {}
}
this type is A<T>; and the question is whether A<T> <: T, which is false.
What we really want here is "self type", so that this type is T. We don't have that in Java.
Usually we use T extends A<T> for "self type"; but it is flawed and inadequate in some use cases.
One remedy for that is T getThis(), as kocko mentioned.
You could simply do a brute cast (T)this, which is obviously correct by the intention of T.
My preferred approach is to simply omit the bound of T, and rename it to This to indicate the purpose of the type variable. Casting (This)this looks obviously correct. See my other post. That approach usually works; but it doesn't work here, since C would need This to have the bound A<This>. The deeper problem is A and C depends on each other, which might be redesigned.

Multiple wildcard bounds

Suppose that I have the following class:
public class Either<A, B> {
public Object get();
}
Either is a type that stores one object of either type A or B. get() retrieves that one object.
The question is whether or not it is possible to use generics to alter the method signature of get() so that the type returned is not just Object, but any common supertype of A and B. For example, an Either<Integer, Long> can have get() return Number, an Either<Deque<T>, Set<T>> can have get() return Iterable<T> or Collection<T>, and so on. (Obviously, an Either<Foo,Foo> should have get() return Foo).
If this is at all possible, if I had Either<List<A>, List<B>>, what is the most specific type get() can return? Is it raw List, wildcard List<?>, or something else entirely?
Java inference do have something similar, we can do
public static <C, A extends C, B extends C> C get(Either<A,B> e)
{ return (C)e.get(); }
inference:
A=Integer, B=Long ==> C=Number
A=List<Integer>, B=List<Long> ==> C=List<? extends Number>
usage:
Either<Integer, Long> x = ...;
get(x); // the return type is Number
However there's probably no way to turn it into an instance method. We would need to write
public class Either<A,B>
public <C super A|B> C get() { ... }
or simply
public A|B get(){ ... }
which is not supported in Java
Why not define an abstract class C, containing as much logic common to A and B as you deem necessary, and refer to that in your Either class:
public class Either<C> {
public C get();
}
That doesn't seem like much of an answer, but since Java erases your type information anyway when compiling (that it to say, your compiled code sees only Object instead of an A or a B), then you are in the best position to define what should be retained in an explicit common class.
As far as I know, it is not possible: your Either<A,B> class makes an assumption about a generic third type (let's call it C), which both A and B would extend: while it is possible to write something like public class Either<A extends MyNonFinalClass, B extends MyNonFinalClass> {}, Java doesn't allow forward-referencing a generic type, so you cannot even write something like Either<A extends C, B extends C, C>. Clearly a shame, as your Either class would really be handy :)
You need to make sure A and B share a common ancestry.
public class Either<A extends CommonAncestor, B extends CommonAncestor> {
public CommonAncestor get() {....}
}
or
public class Either<C, A extends C, B extends C> {
public C get() {....}
}

Java: using generic wildcards with subclassing

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.

Can you require multiple types at once?

Basically I want to do this:
public interface A {
void a();
}
public interface B {
void b();
}
public class SomeClass {
public SomeClass(<A&B> e) { // Note the type here
e.a();
e.b();
}
}
What I did on the commented line is obviously illegal. I know I can just require the passed object to implement interface A, or interface B, but is there a way to do both?
I guess there are workarounds (like requiring the parameter to be of type A and then check if it is also an instanceof B), but that way I don't get help from the compiler. Do you know of any way to do this? Or maybe a smarter workaround...
You can do it with generics enabled. For example, to accept an instance of some class that implements both CharSequence and Appendable:
public <T extends CharSequence & Appendable> void someMethod(T param) {
...
}
Depending on the design, you can do one of the following:
Make A : B or B : A.
Make an interface C : A, B.
Either way you'll want to have contract that includes both a() and b().
Well, there is the <T extends A & B> f(T ab) notation, but you should favour composition over inheritance. You don't really have to extend anything. Just make a type that is the joint union (product) of both types A and B, as follows:
public abstract class P2<A, B> {
public A _1();
public B _2();
}
Sometimes called a product-2, or a "pair" type. You can create a handy constructor for these:
public final class P {
private P() {}
public static <A, B> P2 p(final A a, final B b) {
return new P2<A, B>() {
public A _1() {
return a;
}
public B _2() {
return b;
}
}
}
}
Note that you can use the same object for both arguments, if A and B are interfaces and your object implements both of them:
P2<A, B> both = P.p(o, o);
Or you're free to use two different objects, making the design nice and decoupled.
You'll find this type, as well as products of up to 8 types, included in the Functional Java library. There's also a type called Either<A, B> that is the disjoint union (sum) of two types, such that it holds a value that is of either type A or B (or both).
Just shooting in the dark, I don't know if this is the correct syntax, ie if you have to redeclare the methods in C but what about this:
public interface A {
void a();
}
public interface B {
void b();
}
public interface C extends A, B{}
public class SomeClass{
public SomeClass(C e) { // Note the type here
e.a();
e.b();
}
}
If you have a method that needs two different interfaces as parameters, just make it take two parameters.
public void foo(A a, B b) {
....
}
It’s not that hard, believe me.

Categories

Resources