Unchecked cast abstract base class - java

Can someone explain me, why this cast is unchecked. It should be guaranteed that type T is always derived from Base and so the cast from T to Base should not be unchecked.
abstract class Base
{
private static final Map<Class<? extends Base>, Consumer<Base>> _CONSUMERS = new HashMap<>();
#SuppressWarnings( "unchecked" )
public static <T extends Base> void addConsumer( Class<T> clazz, Consumer<T> consumer )
{
_CONSUMERS.put( clazz, (Consumer<Base>) consumer );
}
}

The type of consumer is Consumer<T> = Consumer<? extends Base>, while the put expects a Consumer<Base>.
You should probably declare your _CONSUMERS map as of type:
Map<Class<? extends Base>, Consumer<? extends Base>>
Java does not recognize situations where objects of type X<? extends T> (or X<? super T>) can be used in place of X<T>, you have to explicitly indicate type bounds (see here a more thorough discussion about this).

Related

Unable to put Class into a generic Map

Here's a visual of the problem:
As can be seen from the visual, the IDE is showing a compile-time error to which it does not allow the class to be inserted into the Map.
Here's a simplified version:
#Override
public <T extends Comparable> void transactPersistentEntityStore(...) {
Map<Class<T>, ComparableBinding> propertyTypeMap = new HashMap<>();
propertyTypeMap.put(EmbeddedArrayIterable.class, EmbeddedEntityBinding.BINDING);
propertyTypeMap.put(EmbeddedEntityIterable.class, EmbeddedEntityBinding.BINDING);
// ...
}
Even if both EmbeddedArrayIterable and EmbeddedEntityIterable implements Comparable
Am I missing or misunderstanding something on generics?
You can simplify the point of the problem to this code snippet:
public <T extends Comparable> void m1(T x) {
Class<? extends Comparable> x1Class = x.getClass();
Class<T extends Comparable> x2Class = x.getClass();
}
Or even to this:
public <T> void m2(T x) {
Class<?> x1Class = x.getClass();
Class<T> x2Class = x.getClass();
}
The line with the variable x2Class has an error in these methods.
This is because the compiler throws away the Generics and thus there is no type T at runtime. T is not reifiable. You cannot obtain the type T at runtime.
Have also a look at this article: Why following types are reifiable& non-reifiable in java?

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...

How to define a Function which flexibly accepts subclasses of declared type

I am trying to design a single arg function that can be applied to subclasses of the declared type:
But when I apply a function like this to a type T as below:
Function<? extends T,Boolean> function;
function.apply(T)
I get the following compilation error:
T cannot be converted to capture#2 of ? extends T
Example of the validation interface I am trying to design:
//Intent is that the function can be applied to T, or any subclass of T
public interface IBeanValidator<T> {
public Function<? extends T, Boolean> getValidation();
}
//Class that implements this interface will accept validators for its type
public interface IValidateableBean<T> {
public void validate(final IBeanValidator<T> validator);
}
//Interface for bean objects, which can be validated with validators designed
//for beans belong to this inheritane hierarchy
public interface IBean extends IValidateableBean<IBean> {
public default void validate(final IBeanValidator<IBean> validator) {
//compilation error occurs here.
validator.getValidation().apply(this);
}
}
Instead of a Function<? extends T, Boolean>, you actually just want a Function<T, Boolean>, which will accept subtypes of T. A Function<? extends T, Boolean> actually refers to some unknown but specific subtype of T, e.g. Function<SubT, Boolean>, which can't necessarily be applied to any T.

Java generics: put() on Map<String,capture#3-of ? extends AbstractClass> is not applicable for the arguments (String, AbstractClass)

I'm trying to implement a sort of intern factory for multiple classes that extend from a common parent. Much of the logic is identical, but it can't really be inherited because the lookups need to be static. The desired syntax is something like:
Car c = AbstractClass.valueOf(Car.class, "Ford");
with Car having specific methods related to cars, but the instances are stored in a common cache. Here's what I have so far. My compile error is on the put in the constructor:
"The method put(String, capture#3-of ? extends AbstractClass) in the type Map is not applicable for the arguments (String, AbstractClass)"
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public abstract class AbstractClass {
private static Map<Class<? extends AbstractClass>, LinkedHashMap<String, ? extends AbstractClass>> map = new HashMap<Class<? extends AbstractClass>, LinkedHashMap<String, ? extends AbstractClass>>();
private static synchronized <T extends AbstractClass> Map<String, T> getNameMap(Class<T> clazz) {
LinkedHashMap<String, T> nameToEnum = (LinkedHashMap<String, T>) map.get(clazz);
if (nameToEnum == null) {
nameToEnum = new LinkedHashMap<String, T>();
map.put(clazz, nameToEnum);
}
return nameToEnum;
}
public static <T extends AbstractClass> T valueOf(Class<T> clazz, String name) {
return getNameMap(clazz).get(name);
}
public static <T extends AbstractClass> Collection<T> VALUES(Class<T> clazz) {
return getNameMap(clazz).values();
}
public static <T extends AbstractClass> Set<T> SORTED_VALUES(Class<T> clazz) {
return new TreeSet<T>(getNameMap(clazz).values());
}
AbstractClass(String name) {
AbstractClass.getNameMap(this.getClass()).put(name, this);
}
}
According to the javadoc for Object.getClass(), the returned type is a wildcard based compile-time type of the expression. Since the compiler only knows that this returns an AbstractClass instance, this.getClass() returns Class<? extends AbstractClass>.
This means your call to getNameMap in the constructor will return a Map<String, ? extends AbstractClass>. Which means that, while the returned Map has values of a specific (non-wildcard) type, that exact type isn't known at compile-time; the compiler only knows the Map's values are required to be either AbstractClass or something that inherits from AbstractClass. So the compiler can't safely add this as a value, since it isn't known at compile-time which subtype of AbstractClass this represents.
To use a simpler example: if a method returned Map<String, ? extends Number> then the compiler wouldn't know whether it was safe to add an Integer to the Map, because the Map's actual, non-wildcard type might be Map<String, Double>, Map<String, Short>, etc.
As for a solution: I don't think there is a way to have a Map use generics to match each individual key's type with its corresponding value's type. I would forget about using bounded types on the inner Maps' values, and use dynamic casting instead:
private static Map<Class<? extends AbstractClass>, Map<String, AbstractClass>> map = new HashMap<>();
private static synchronized Map<Class<? extends AbstractClass>, Map<String, AbstractClass>> getNameMap(Class<T> clazz) {
// same as before
}
public static <T extends AbstractClass> T valueOf(Class<T> clazz, String name) {
return clazz.cast(getNameMap(clazz).get(name));
}
If you just want to store anything that is an AbstractClass, just declare your map as
private static Map<Class<? extends AbstractClass>, LinkedHashMap<String, AbstractClass>> map =
new HashMap<Class<? extends AbstractClass>, LinkedHashMap<String, AbstractClass>>();
This would allow you to store any instance of AbstractClass or its subclasses in the inner map, against AbstractClass or one of its sub class.
Your problem can basically be boiled down to this:
Given a method with this signature:
public static <T> void foo(T x, Class<T> y);
and a variable of any reference type:
<any reference type> bar;
it is impossible to pass bar and bar.getClass() to this method:
foo(bar, bar.getClass()); // error
even though it is provable that there always exists some T for which it is correct (i.e. T = the actual runtime type of bar).
It is due to the special case in the language for the type of .getClass() that causes this problem.
I can think of two ways to solve this:
1) Cast the class object to be parameterized by the same type as the reference (even though this is technically not true):
AbstractClass(String name) {
AbstractClass.getNameMap((Class<AbstractClass>)this.getClass()).put(name, this);
}
2) Cast the object to the same type as the parameter of the class method. This will require a capture helper due to the wildcard in the class's type:
private static <T> void helper(Class<T> clazz, String name, Object obj) {
AbstractClass.getNameMap(clazz).put(name, (T)obj);
}
AbstractClass(String name) {
helper(this.getClass(), name, this);
}
(if you don't want that unchecked cast you can do AbstractClass.getNameMap(clazz).put(name, clazz.cast(obj));)

Categories