Generics with Wildcards (Map<? extends A, List<? extends B>>) - java

Consider the following code:
public interface A {};
public class AImpl implements A {};
public interface B {};
public class BImpl implements B {};
public interface Service{
Map<? extends A, List<? extends B>> get();
}
Why does the following implementation of Service not compile?
public class ServiceImpl implements Service {
public Map<AImpl, List<BImpl>> get() {
return null;
}
}
Compiler error:
The return type is incompatible with Service.get()
But the following code compile:
public interface Service{
List<? extents B> get();
}
public class ServiceImpl implements Service{
public List<BImpl> get(){
return null;
}
}

Because <? extends BaseType> means "some unspecified sub-type BaseType", and class Sub extends BaseType, while sub-type of BaseType, is not it. Read Java Generics FAQ, in particular starting from Wildcard Capture section, for more details.
You should generify your code properly:
public interface Service<K extends A, V extends B> {
Map<K, List<V>> get();
}
public class ServiceImpl implements Service<AImpl, BImpl> {
#Override
public Map<AImpl, List<BImpl>> get() {
return null;
}
}

The return type of the Service#get() method is specified as
Map<? extends A, List<? extends B>> get();
And you are trying to return a
Map<AImpl, List<BImpl>>
You can use covariant return types. And it seems like you thought this would be the case here. But the problem is that this covariance does not apply to the generic type parameters. Although List<BImpl> is a subtype of List<? extends B>, this does not mean that Map<AImpl, List<BImpl>> is a subtype of Map<? extends A, List<? extends B>>.
A structurally similar but simpler case is that List<Integer> is not a subtype of List<Number>.
You could change the return type in the Service interface to
Map<? extends A, ? extends List<? extends B>> get();
to make it work.

ServiceImpl cannot be an interface because your Implementation cannot be in an interface; Change it to a base base class and try it.

What do you write?
Map<? extents A, List<? extents B> get();
java doesn't know anything about extents
At least use extends

Related

Issue with interface as Map key & value

In a library project, I have :
public interface InterfaceA {
}
public interface InterfaceB {
}
public void myMethod(Map<? extends InterfaceA, List<? extends InterfaceB>> map) {
//do something
}
Then I have another project (having this library as a dependency) that contains two object implementing these interfaces :
public class ObjectA implements InterfaceA {
}
public class ObjectB implements InterfaceB {
}
When I try to call the library method myMethod like this :
HashMap<ObjectA, List<ObjectB>> hashMap = new HashMap<>();
//populate hashmap
myMethod(hashMap);
I get a compilation warning saying there is an argument mismatch.
What am I missing here ? Does it have something to do with the map ?
EDIT :
The exact error (it's not a warning actually) is :
incompatible types: HashMap<ObjectA,List<ObjectB>> cannot be converted to Map<? extends InterfaceA,List<? extends InterfaceB>>
Generics are invariant.
If your method declares:
Map<? extends InterfaceA, List<? extends InterfaceB>>
Then the second type parameter has to be exactly List<? extends InterfaceB>.
You can fix it by using:
Map<? extends InterfaceA, ? extends List<? extends InterfaceB>>
Instead.
You either modify your Hashmap creation for this:
Map<? extends InterfaceA, List<? extends InterfaceB>> hashMap = new HashMap<>();
or modify your method definition for this:
public <A extends InterfaceA, B extends InterfaceB> void myMethod(Map<A, List<B>> map) {
//do something
}
Declare your map as
HashMap<ObjectA, List<? extends InterfaceB>> hashMap = new HashMap<ObjectA, List<? extends InterfaceB>>();

Java - Defining a member that extends class A and implements interface B

I have a variable that must meet two conditions, and I want to set them in the definition
I know that I can define either condition with an individual variable, like in any of these examples
private Class<? extends A> variable; //or
private A variable; //or
private Class<? extends B> variable; //or
private B variable;
But is there a way to have the variable meet both conditions?
I was hoping for something like this
private Class<? extends A implements B> variable;
But I can't find any way to do this without typecasting when I need to call it or storing multiple copies of it
You can declare type parameters that have multiple bounds, such as:
public static <T extends A & B> void test(Class<T> clazz)
But you cannot declare a variable that has multiple bounds:
private Class<? extends A & B> variable; // doesn't work
You can create an abstract class C that extends A and implements B, so that only one bound is required.
abstract class C extends A implements B {}
Then:
private Class<? extends C> variable;
While Java does not directly support intersection types like A&B, such types do appear in type parameter bounds and capture conversions. We can express A&B with a layer of abstraction.
public class ValueAB<T extends A&B>
{
public final T v;
// constructor ...
}
public class ClassAB<T extends A&B>
{
public final Class<T> clazz;
// constructor ...
}
Instead of A&B, Class<? extends A&B>, we use wrappers ValueAB, ClassAB
ClassAB<?> clazz = new ClassAB<>(Foo.class);
ValueAB<?> value = new ValueAB<>(clazz.c.newInstance());
value.v.methodOfA();
value.v.methodOfB();
This solution would require a wrapper for each combination of As and Bs.
Another solution is to use only A as type parameter bound; B will be supplied by wildcard bound. This is probably better if you need to express multiple A&B1, A&B2, ... types at use site.
public class ValueA<T extends A>
{
public final T v;
...
}
public class ClassA<T extends A>
{
public final Class<T> c;
...
}
---
ClassA<? extends B> clazz = new ClassA<>(Foo.class);
ValueA<? extends B> value = new ValueA<>(clazz.c.newInstance());
If it's confusing how wildcard works in these cases, see my article on wildcard
A 3rd solution is free of A or B at declaration site of wrappers; the use site provides A and B.
public class Value<T extends S, S>
{
public final T v;
...
}
public class Clazz<T extends S, S>
{
public final Class<T> c;
...
}
---
Clazz<? extends A, B> clazz = new Clazz<>(Foo.class);
Value<? extends A, B> value = new Value<>(clazz.c.newInstance());
This is however probably too confusing.

Generic Chaos Java

I use two Interfaces:
public interface Receiver<T> {
public void receive(T obj);
public Set<Class<? extends T>> getInterests();
}
public interface Distributor<T> extends Receiver<T> {
public void register(Receiver<T> receiver);
}
My problem that I want to register a Distributor in a Distributor e.g.
Distributor<Object> ==register==> Distributor<String>
My first thought was to change the register method to register(Receiver<? extends T> receiver). But if I want to get the Classes the receiver is intrested in the Method getInterests would return something like
Set<Class<? extends ? extends T>>.
Indirect I get something like Set<Class<? extends T>> but I experienced that transitiv wildcards are not possible in Java.
Got anyone an idea?
EDIT: As an example:
public void register(Receiver<? extends T> receiver){
Set<Class<? extends T>> interests = receiver.getInterests();
//Problem because receiver.getInterests is
//Set<Class<? extends ? extends T>>
...
}
Your problem is that Java generics are completely invariant, unless you make them variant using ? extends or ? super wildcards.
A Set<Class<? extends T>> can only hold expressions of exactly the compile-time type Class<? extends T>. Class<String> is not the same type as Class<? extends T> (even though it is convertible to that type).
You want a set that can hold any type that is convertible to Class<? extends T>.
That would be a Set<? extends Class<? extends T>>
You could add a helper method that uses a type variable instead of wildcard
public void register(Receiver<? extends T> receiver)
{
register2(receiver);
}
private <S extends T> void register2(Receiver<S> receiver)
{
Set<Class<? extends S>> interests = receiver.getInterests();
...
}
On the other hand, method
public Set<Class<? extends T>> getInterests();
is probably intended to return a covariant Set, or, read-only set. Ideally wildcard should be used
public Set<? extends Class<? extends T>> getInterests();
but I know, there are too many damn wildcards...

Java recursive generics class wildcard matching

Having these generic interface and class:
interface TestIntf<T extends TestIntf<T>>
{
void test(T param);
}
class TestImpl<T extends TestIntf<T>> implements TestIntf<T>
{
#Override
public void test(T param) { System.out.println(param); }
}
This fails:
Class<? extends TestIntf<?>> clz = TestImpl.class;
(Type mismatch: cannot convert from Class<TestImpl> to Class<? extends TestIntf<?>>)
Why? How to properly provide a reference to TestImpl class to match Class<? extends TestIntf<?>>?
You can't. Use an unsafe cast.
Class<? extends TestIntf<?>> clz = (Class<? extends TestIntf<?>>) TestImpl.class;
or don't use the inner generics:
Class<? extends TestIntf> clz = TestImpl.class;
Update: When it regards annotations, there is nothing you can do - the annotation has to be changed. You cannot have a class literal represent a generic type.

Generic classes in Java (type-safely) depending on each other

I want to create an abstract collection class (called Space) and an
abstract element class (called Atom). Instances of both have to know each other (exactly typed).
That's the problem.
abstract class Space<A extends Atom>{
// ...
}
abstract class Atom<S extends Space>{
// ...
}
Not good:
"A extends Atom" means any Atom, but not a strongly typed one
"S extends Space" means any Space, but not a strongly typed one
I can't reach complete type-safety with the following attempts either:
abstract class Space<A extends Atom<? extends Space>>
abstract class Atom<S extends Space<? extends Atom>>
abstract class Space<S, A extends Atom<S extends Space<A>>>
abstract class Atom<A, S extends Space<A extends Atom<S>>>
and so on ...
Remember, these two classes are abstract, and I want that any possible
two subclasses are typed according to each other.
That means, the classes SomeSpace and SomeAtom in the following example
must have a strong "type knowledge" of each other:
class SomeSpace extends Space<SomeAtom>
class SomeAtom extends Atom<SomeSpace>
This works for me, although I got really confused about all those generic constraints. Which means I can't guarantee that it does what it's supposed to do:
interface ISpace<S extends ISpace<S, A>, A extends IAtom<S, A>> {
List<? extends IAtom<S, A>> getList(); //// CHANGED
}
interface IAtom<S extends ISpace<S, A>, A extends IAtom<S, A>> {
S getSpace();
}
abstract class Space<S extends Space<S, A>, A extends Atom<S, A>>
implements ISpace<S, A> {
private final List<Atom<S, A>> atoms = new LinkedList<Atom<S, A>>(); ////CHANGED
public Space() {
}
public Space<S, A> getSpace() {
return this;
}
#Override
public List<Atom<S, A>> getList() { //// CHANGED
return atoms;
}
}
abstract class Atom<S extends Space<S, A>, A extends Atom<S, A>>
implements IAtom<S, A> {
private final S space;
public Atom(S someSpace) {
this.space = someSpace;
space.getList().add(this);
}
#Override
public S getSpace() {
return space;
}
public Atom<S, A> getAtom() {
return this;
}
}
class Space1 extends Space<Space1, Atom1> {
public Space1() {
}
}
class Atom1 extends Atom<Space1, Atom1> {
public Atom1(Space1 someSpace) {
super(someSpace);
}
}
abstract class Space<S extends Space<S,A>, A extends Atom <A, S>> {}
abstract class Atom <A extends Atom <A,S>, S extends Space<S, A>> {}
Or, I guess, if you prefer
abstract class Space<S extends Space<S,A>, A extends Atom<S, A>> {}
abstract class Atom <S extends Space<S,A>, A extends Atom<S, A>> {}
I wouldn’t try to solve that problem with generics. Instead, supply a Factory that always creates matching objects.
class UniverseFactory {
public Space getSpace();
public Atom getAtom();
}
You could then perform a type check in your implementations to ensure that only matching objects are used.
The only way to make parameterized types in Java know anything at all about their actual concrete type is to pass in a type parameter at construction:
public Foo<T>(class<T> klass, // other parameters
The meta answer is that circular type dependencies are questionable, and indicate a need to revisit your design. Generally, a better solution is to have a hierarchical dependency on a third type:
public class SomeAtom extends Atom<Something>
public class SomeSpace extends Space<Something>
The meta-meta answer is that "type safety" has its limitations, no matter what the language: http://www.kdgregory.com/index.php?page=java.generics.cpp
Thank you, "Tom Hawtin - tackline", I've incorporated your answer,
and it fits. Additionally, following code demonstrates the (slightly strange)
necessity to alter List type parameters (if you need List of atoms)
interface ISpace<S extends ISpace<S, A>, A extends IAtom<S, A>> {
List<IAtom<? extends S, ? extends A>> getList();
}
interface IAtom<S extends ISpace<S, A>, A extends IAtom<S, A>> {
S getSpace();
}
abstract class Space<S extends Space<S, A>, A extends Atom<S, A>>
implements ISpace<S, A> {
private final List<IAtom<? extends S, ? extends A>> atoms =
new LinkedList<IAtom<? extends S, ? extends A>>();
public Space() {
}
#Override
public List<IAtom<? extends S, ? extends A>> getList() {
return atoms;
}
}
abstract class Atom<S extends Space<S, A>, A extends Atom<S, A>>
implements IAtom<S, A> {
private final S space;
public Atom(S someSpace) {
this.space = someSpace;
/// THIS WILL NOT WORK WITHOUT THOSE STRANGE LIST TYPE PARAMETERS
space.getList().add(this);
}
#Override
public S getSpace() {
return space;
}
}
class Space1 extends Space<Space1, Atom1> {
public Space1() {
}
}
class Atom1 extends Atom<Space1, Atom1> {
public Atom1(Space1 someSpace) {
super(someSpace);
}
}
The idea behind the whole thing is:
I need element objects which know their container type-safely
and container objects which know their elements type-safely.

Categories