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

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.

Related

Java generic method optional type

I have a generic method in Java:
public static <T extends C> ArrayList<<MyClass<T>> methodOne(parameter1)
Currently, I use this method to get an ArrayList of a specific type of MyClass as follows (A and B are subclasses of C):
ArrayList<MyClass<A>> result = methodOne<A>(param1);
or
ArrayList<MyClass<B>> result = methodOne<B>(param1);
Now I have another need and it's for an ArrayList that holds MyClass of both types:
ArrayList<MyClass> result = methodOne<MyClass>(param1);
However, I cannot return ArrayList<MyClass> from methodOne because it declares that it returns an ArrayList<MyClass<T>> Object.
I can fix this by changing methodOne to non-generic:
pubic static ArrayList<MyClass> methodOne(parameter1)
However, I feel safer when I can specify the type of MyClass when possible. And if I use the above declaration then I will not be able to do something like:
ArrayList<MyClass<A>> result = methodOne<A>(param1);
Is there any way I can keep the current generic method and be able to specify a type for MyClass when I want and be able to leave out the type in other situations (i.e.: when the method call fills the ArrayList with both types of MyClass)?
However, the ArrayList that will hold MyClass of both types will hold MyClass<A> Objects and MyClass<B> Objects (not MyClass<superclass> Objects)
A list that holds both MyClass<A> and MyClass<B> should have the type:
List<MyClass<? extends C>>
You can then add MyClass<A> and MyClass<B> elements to your list.
If you need your method to return a different type at different times, it must depend in some way on the parameters to the method. So for instance, if methodOne() takes a MyClass instance as an argument, you could define a method like this (note the <T> declaration, making this a generic method):
public <T> List<MyClass<T>> methodOne(MyClass<T> param, ...)
Then you can have methodOne() return lists of the same type as the object that is passed:
List<MyClass<A>> result1 = methodOne(instanceOfA, ...);
List<MyClass<C>> result = methodOne((MyClass<C>)instanceOfA, ...);
If you do not intend to pass in an instance of the desired type, you can still get away with it by passing in the Class of that type, like so:
public <T> List<MyClass<T>> methodOne(Class<T> clazz, ...)
And calling:
List<MyClass<A>> result1 = methodOne(A.class, ...);
List<MyClass<C>> result = methodOne(C.class, ...);
Which alternative you prefer depends on your use case.
You have to use this method signature:
<T extends C> ArrayList<MyClass<? extends T>> methodOne(int param1)
which will return a List of MyClass-objects of C and its subclasses.
Use it like this:
ArrayList<MyClass<? extends C>> resultC = methodOne(123);
resultC.add(new MyClass<A>());
resultC.add(new MyClass<B>());
Full example code:
import java.util.ArrayList;
interface C {}
class A implements C {}
class B implements C {}
class MyClass<X> {}
public class Generic {
public static void main(String[] args) {
ArrayList<MyClass<? extends A>> resultA = methodOne(123);
resultA.add(new MyClass<A>());
ArrayList<MyClass<? extends B>> resultB = methodOne(123);
resultB.add(new MyClass<B>());
ArrayList<MyClass<? extends C>> resultC = methodOne(123);
resultC.add(new MyClass<A>());
resultC.add(new MyClass<B>());
}
static <T extends C> ArrayList<MyClass<? extends T>> methodOne(int param1) {
return null;
}
}
You cannot do that, because even if class A extends class B, List<A> does not extends List<B>. This is because a A object supports all attributes and methods of B with same signature.
But List<B> has a add method accepting a B object, where List<A> only accepts A elements.
But the addAll method has a nice signature (for a List<E>) :
boolean addAll(Collection<? extends E> c)
So if it is acceptable, you could do :
ArrayList<MyClass<? extends abstractAncestor>> l = new ArrayList<MyClass<? extends abstractAncestor>>();
l.addAll(method1<MyClass<A>>(param1));
l.addAll(method1<MyClass<B>>(param1));

Java generics: <B extends BaseB> does not match <? extends BaseB>

I have two isomorphic type hierarchies. The base type of the first one is BaseA and the base type of the second one is BaseB. I know how to transform any object of any subclass of BaseB to its corresponding subtype of BaseA. I want to implement a method which takes object of type BaseB determines its class and constructs an object of the corresponding subtype of BaseA. Example code:
public interface BaseA...
public interface BaseB...
public class DerA implements BaseA...
public class DerB implements BaseB...
...
public interface Transform<A,B> {
A toA (B b);
}
public class DerAtoDerB implements Transform<DerA,DerB> {
DerA toA (DerB b){...}
}
public class Transformations {
private static Map<Class<?>, Transform<? extends BaseA, ? extends BaseB>> _map =
new HashMap<>();
static {
_map.put(DerB.class, new DerAtoDerB());
}
public static <B extends BaseB> BaseA transform(B b){
Transform<? extends BaseA, ? extends BaseB> t = _map.get(b.getClass());
return t.toA(b); // Compile error: Transform<A,B#2> cannot be applied to given types
}
Why <B extends BaseB> is not compatible with <? extends BaseB> ? Also if I try implementing the static transform method like this:
public static BaseA transform(BaseB b){
Transform<? extends BaseA, ? extends BaseB> t = _map.get(b.getClass());
return t.toA(b); // Compile error: Transform<A,B> cannot be applied to given types
}
I get a compilation error: Transform<A,B> cannot be applied to given types
Can anyone explain me what I am doing wrong with Generics?
The problem is that in the transform method the compiler can't know that the type parameter B extends BaseB and the second type parameter in the Transform class (? extends BaseB) that was gotten from the map actually represent the same subclass of BaseB. Nothing stops you from storing an incompatible type in the map:
_map.put(DerB.class, new AnotherDerAtoAnotherDerB()); // the types don't match
You are the one who guarantees that the types in the map match, so you need to tell the compiler by casting it to the correct type:
#SuppressWarnings("unchecked")
public static <B extends BaseB> BaseA transform(B b) {
Transform<? extends BaseA, B> t =
(Transform<? extends BaseA, B>)_map.get(b.getClass());
return t.toA(b);
}
When the compiler encounters a variable with a wildcard in its type it knows that there must have been some T that matches what was sent in. It does not know what type T represents, but it can create a placeholder for that type to refer to the type that T must be. That placeholder is called the capture of that particular wildcard.
I don't know why the compiler can't figure out that capture<? extends BaseB> could be capture<?> extends BaseB, maybe something with type erasure?
I would instead implement it like this:
interface BaseA {}
interface BaseB {}
class DerA implements BaseA {}
class DerB implements BaseB {}
interface Transform {
BaseA toA(BaseB b);
}
class DerAtoDerB implements Transform {
public BaseA toA(BaseB b) { return new DerA(); }
}
class Transformations {
private static Map<Class<?>, Transform> _map =
new HashMap<>();
static {
_map.put(DerB.class, new DerAtoDerB());
}
public static<B extends BaseB> BaseA transform(B b) {
Transform t = _map.get(b.getClass());
return t.toA(b);
}
}
? means unknown type.
When a variable is of type X you can assign it a value of type X or any subtype of X but "? extends X" means something else.
It means there is an unknown type that may be X or any subtype of X. It is not the same thing.
Example:
public static Transform<? extends BaseA, ? extends BaseB> getSomething(){
// My custom method
return new Transform<MySubclassOfA, MySubclassOfB>(); // <-- It does not accept BaseB, only MySubclassOfB
}
public static BaseA transform(BaseB b){
Transform<? extends BaseA, ? extends BaseB> t = getSomething();
return t.toA(b); // <--- THIS IS WRONG, it cannot accept any BaseB, only MySubclassOfB
}
In the example the compiler does not know if t admits any BaseB or what but I shown an example where it doesn't.
This thing compiles:
package com.test;
import java.util.HashMap;
import java.util.Map;
interface BaseA{}
interface BaseB{}
class DerA implements BaseA{}
class DerB implements BaseB{}
interface Transform<A,B> {
A toA (B b);
}
class DerAtoDerB implements Transform<BaseA,BaseB> {
public DerA toA(DerB b){ return null; }
#Override
public BaseA toA(BaseB baseB) {
return null;
}
}
public class Transformations {
private static Map<Class<?>, Transform<? extends BaseA, ? super BaseB>> _map = new HashMap<Class<?>, Transform<? extends BaseA, ? super BaseB>>();
static {
_map.put(DerB.class, new DerAtoDerB());
}
public static <B extends BaseB> BaseA transform(B b){
Transform<? extends BaseA, ? super BaseB> t = _map.get(b.getClass());
return t.toA(b);
}
}
The changes I made to your code are the following:
DerAtoDerB now implements Transform<BaseA,BaseB>, instead of Transform<DerA,DerB>
Type of second generic parameter of Map has changed to Transform<? extends BaseA, ? super BaseB> - pay attention to use of super instead of extends - it's the opposite type bound.
Main concept of Java generics: if ChildClass extends ParentClass it DOES NOT mean YourApi<ChildClass> extends YourApi<ParentClass>. E.g.:
NumberTransform<String, ? extends Number> intTransform = new IntegerTransform<String, Integer>(); // work with Integer numbers only
NumberTransform<String, ? extends Number> longTransform = new LongTransform<String, Long>(); // work with Long numbers only
longTransform.toA((Integer) 1); // you are trying to make this and got compilation error.
To help compiler replace your t initialization:
Transform<? extends BaseA, B> t = (Transform<? extends BaseA, B>) _map.get(b.getClass());

Why producer in Collections.max() is a bounded wildcard? [duplicate]

In Java, the Collections class contains the following method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)
Its signature is well-known for its advanced use of generics,
so much that it is mentioned in the Java in a Nutshell book
and in the official Sun Generics Tutorial.
However, I could not find a convincing answer to the following question:
Why is the formal parameter of type Collection<? extends T>, rather
than Collection<T>? What's the added benefit?
Type inference is a tricky topic that I'll admit that I don't know that much about. However, examine this example:
public class ScratchPad {
private static class A implements Comparable<A> {
public int compareTo(A o) { return 0; }
}
private static class B extends A {}
private static class C extends B {}
public static void main(String[] args)
{
Collection<C> coll = null;
B b = Scratchpad.<B>min(coll);
}
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c) {
return null;
}
//public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
// return null;
//}
}
Consider that the first signature of min() allows the call to compile whereas the second does not. This isn't a very practical example, since one must ask why I would be explicitly typing the method to <B>, but perhaps there is an implicit inference where B would be the inferred type.
One benefit of the ? is that it prohibits additions of items to the Collection
I think it actually doesn't give you anything more for this method, however its a good habit to get into when T is part of the class and not just a static method.
They are including it here so it can become the new convention where every generic should be extended by ?
A class of T should follow PECS: What is PECS (Producer Extends Consumer Super)?
But a static method doesn't need to (at least the parameters, the return value should always)
This is to support a legacy signature of the method in Java 1.4 ( and before ).
Prior to Java 5 the signature for these methods was
public static Object min ( Collection c );
With multiple bounds the erasure rules make the first bound the raw type of the method, so without Object & the signature would be
public static Comparable min ( Collection c );
and legacy code would break.
This is taken from O'Reilly's Java Generics and Collections book, chapter 3.6
Building on the comments I put on Mark's answer, if you have something like
class Play {
class A implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
class B extends A {
}
class C extends A {
}
public static <T extends Object & Comparable<? super T>> T min(
Collection<? extends T> c) {
Iterator<? extends T> i = c.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static List<? extends A> getMixedList() {
Play p = new Play();
ArrayList<A> c = new ArrayList<A>();
c.add(p.new C());
c.add(p.new B());
return c;
}
public static void main(String[] args) {
ArrayList<A> c = new ArrayList<A>();
Collection<? extends A> coll = getMixedList();
A a = Play.min(coll);
}
}
It's clearer that min returns an object of type A (the actual signature is <A> A Play.min(Collection<? extends A> c) ). If you leave min(Collection<T>) without the extends part then Play.min(coll) will have the following signature <? extends A> ? extends A Play.min(Collection<? extends A> c) which isn't as clear.

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

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

enforce the type of an upper bounded wildcard?

I have a variable that has several upper bounded wildcards, like so:
private Map< Class< ? extends MyClass1 >, List< ? extends MyClass2< ? extends MyClass3, ? extends MyClass1> > > _variableName;
Is there any way to enforce that the bound value ? extends MyClass1 be the same for the Type of the Class class and the 2nd param of the MyClass2 class?
Yes:
public class Foo<T extends MyClass1> {
private Map< Class<T>, List<? extends MyClass2<? extends MyClass3, T>>> bar;
...
}
You could also do this with a generic method. It depends on where you want to make the guarantee (and by extension, where the Map is instantiated), when defining the class or when calling a method that instantiates this Map.
UPDATE:
In response to the (correct) observation that this map will only contain one element, perhaps the questioner had this in mind instead:
public class Foo {
private Map<Class<? extends MyClass1>, List<? extends MyClass2<? extends MyClass3, ? extends MyClass1>>> bar;
public <T extends MyClass1> void add(Class<T> myClass, List<? extends MyClass2<? extends MyClass3, T>>> myList) {
bar.put(myClass, myList);
}
...
}
Assuming this is the only way to add elements to your private map, then that ensures the types always match.

Categories