Dependencies between generic classes - java

I have the following Interfaces:
public interface Assembler<T, S> {
S assemble( T val);
}
public interface Slicer<T, V> {
V[] slice(T val);
}
I want to have an Assembler instance use a Slicer instance and call it’s slice(). I have the following:
public class MyAssembler<T, S> implements Assembler<T, S> {
private final Slicer<T, V> slicer;
//ctor
public MyAssembler() {
slicer = new MySlicer<T, V>();
}
#Override
public S assemble(T val) {
V[] v = mySlicer.slice(val);
}
This doesn’t compile because the V type is not known (cannot be resolved to a type) in MyAssembler. I cannot change the Assembler interface to be Assembler<T, S, V>. Is there another way I can define the dependency? This is not an issue with non generic classes. Even if a static factory method is used to get the reference to Slicer, the problem of unknown V would still exist. Any suggestions? If this cannot be done, can anyone recommend a different approach or design pattern that allows for an Assembler to call the Slicer's slice()?

Will Assembler always have Slicer as one of its two generics? If so, you only need to define one generic, and have the Slicer as a non-generic member variable.
If, however, the generic types may or may not be Slicer, you can implement special handling for when one of them is Slicer with reflection, especially if (v instanceof Slicer) and then casting to Slicer if true.

Since your S and V are generic, you can exchange them for any other type, even other generics. You can do:
public class MyAssembler<T, S> implements Assembler<T, S> {
private final Slicer<T, S> slicer;
public MyAssembler() {
slicer = new MySlicer<T, S>();
}
#Override
public S assemble(T val) {
S[] v = slicer.slice(val);
return v[0]; // for example
}
}
What I did is to define T and S as the same type. In my own implementation, I can do this without problems.

Reposting Sotirios Delimanolis' comment as the answer.
To allow for the use of V in MyAssembler, declare MyAssembler<T, S, V> extends Assembler<T, S>. To use it, instantiate with for ex: Assembler<Integer, Integer> asmblr = new MyAssembler<Integer, Integer, Integer>.

Inheritance will solve your problem instead of Composition in this case as shown below:
public class MyAssembler<T,S,V> extends MySlicer<T,V> implements Assembler<T,S> {
public MyAssembler() {
}
#Override
public S assemble(T val) {
V[] v = this.slice(val);
...
}
}

Related

Using self-referential generic types in Java

Consider the following Java method:
<T extends List<T>> List<T> getMyList() {
return Collections.emptyList();
}
I can assign its output to a variable with a raw type, like so:
List x = getMyList();
List<List> y = getMyList();
But, I can't think of any way to assign its output to a fully parameterized type. In particular, I can't think of a non-raw, concrete type T that would satisfy List<T> z = getMyList();
Can we create such a T ?
If not, why not?
For context, I created this question while trying to understand how Enums are implemented in Java.
Here's an example of a concrete type that both works and starts to hint at a possible use-case (registration of some sort). The type consists acts like both an instance of some type, and as a container for all instances of that type.
public class WeirdEnum extends AbstractList<WeirdEnum> {
private static List<WeirdEnum> underlyingList = new ArrayList<>();
#Override
public WeirdEnum get(int index) { return underlyingList.get(index); }
#Override
public int size() { return underlyingList.size(); }
static <T extends List<T>> List<T> getAList() {
return Collections.emptyList();
}
public WeirdEnum() {
underlyingList.add(this); // Sufficient for our example but not a good idea due to concurrency concerns.
}
static List<WeirdEnum> foo = WeirdEnum.getAList();
}
Not sure if I fully understand your question, but here's an example:
class Example<T> implements List<Example<T>> {
...
}
...
List<Example<String>> list = getMyList();
Every enum in Java extends from the base-enum-class Enum<T extends Enum<T>>, where T is the actual type of the implementing enum.
When writing SomeClass<T extends SomeClass<T>> you can enforce that the type-parameter is always the implementing class itself.
Let's say you have this interface:
public interface MyInterface<T extends MyInterface<T>> {
T getSelf();
}
And this implementing class:
public class MyClass implements MyInterface<MyClass> {
public MyClass getSelf() {
return this;
}
}
In MyClass it is not possible to use any other type-parameter than MyClass itself.

How to use class instead of interface for lambda param

Right now I have this:
public static interface AsyncCallback<T, E> {
public void done(E e, T v);
}
I want to convert it to this so I use a boolean property on it:
public abstract static class AsyncCallback<T, E> {
boolean shortcircuit = false;
public abstract void done(E e, T v);
}
but now I am getting errors:
Inconvertible types; cannot cast '' to 'E'
and
no instance(s) of type variable(s) T exist so that List conforms to
AsyncTask
the code I have that generates the errors is based off passing lambdas. Does anyone know why converting the interface to a class causes problems? Even if I comment out the shortcircuit field and just have the done method definition, same errors arise.
You cannot use class instead of Interface ( Precisely to say Fuctional Interface).
See the link to know why do we need functional Interface to work with lambda in java.
In your case you are trying to use a class , which will obviously have
name, isn't. but to use lambda we have to use anonymous functions
which don't have name and type.
I solved this problem by keeping the interface but also using a class:
public static interface AsyncTask<T, E> {
public void run(AsyncCallback<T, E> cb);
}
public static interface IAsyncCallback<T, E> {
public void done(E e, T v);
}
public static abstract class AsyncCallback<T, E> implements IAsyncCallback<T, E> {
public boolean shortcircuit = false;
}
in circumstances where I must use an interface, I use the IAsyncCallback interface, where I can use a class, I use AsyncCallback class.

Java generics - cast assignable capture type to subclass

I have the following scenario in Java generics:
public abstract class A<T> {
protected final Class<T> typeOfX;
public A(final Class<T> typeOfX) {
this.typeOfX = typeOfX;
}
public abstract void load(final T x);
}
public class AnyA<S> extends A<S> {
private final Map<String, A<? extends S>> map;
public AnyA(final Class<S> superTypeOfX,
final Map<String, A<? extends S>> map) {
super(superTypeOfX);
this.map = map;
}
#Override
public void load(final S superx) {
for (final A<? extends S> a: map.values())
if (a.typeOfX.isAssignableFrom(superx.getClass())) //Here I want to say: "if superx can be casted to a.typeOfX".
a.load(a.typeOfX.cast(superx)); //Here I want to cast superx to a.typeOfX (so as to call the load method). Here's the compile error.
}
}
I'm getting the error:
incompatible types: S cannot be converted to CAP#1
where S is a type-variable:
S extends Object declared in class AnyA
where CAP#1 is a fresh type-variable:
CAP#1 extends S from capture of ? extends S
AnyA is a composite A, i.e. is an A which maintains several other A instances.
AnyA in its load(...) method shall decide which of the maintained A instances should be used to "pass the loading process to" of the argument.
In other words, AnyA is responsible for finding the correct A to load the argument.
But also AnyA is an A because it handles loading the argument.
My question is:
Why is this cast not possible, by the time I know that S is a sub-class of T and all A instances in AnyA can load a subclass of S?
How can I overcome this problem without changing the class diagram too much?
I have read about "helper methods" but cannot match the example shown there to my problem.
I'm using NetBeans IDE with Java SDK 8.
Note that regardless of what you do, the code is not "syntactically type safe" in any case. There is an unchecked cast, and the only safety belt that prevents this from going wrong is the isAssignableFrom check.
(That is often OK, I'm just mentioning it for completeness)
The reason for the error may be more obvious when you pull the lines apart (here, S stands for SuperType, according to the Type Parameter Naming Conventions - please follow them!)
A<? extends S> a = ...;
S s = a.typeOfX.cast(s);
a.load(s);
The A<? extends S> intuitively means that it is an A that can accept an unknown type in its load method. You know that it extends type S, but you do not know which type this is.
It may become blatantly obvious when you insert Object for S:
A<String> specificA = ...;
// So the "specificA" can load "String" objects. Then this is fine:
A<? extends Object> a = specificA;
Object s = a.typeOfX.cast(s);
// But here's the error: "s" is only an Object, and not a String!
a.load(s);
I think the main point of confusion (and the main reason for the question) was the following: When calling
Object s = a.typeOfX.cast(s);
and typeOfX is String.class, then the return type of the cast will not be String, but only the type that the compiler can infer at this point. And this is Object, in the example above.
However, you already referred to the Helper Methods, and indeed, with some trickery, you can make this compile,
but... (see notes below)
import java.util.Map;
abstract class A<T>
{
protected final Class<T> typeOfX;
public A(Class<T> typeOfX)
{
this.typeOfX = typeOfX;
}
public abstract void load(T x);
}
class AnyA<S> extends A<S>
{
private final Map<String, A<? extends S>> map;
public AnyA(Class<S> superTypeOfX,
Map<String, A<? extends S>> map)
{
super(superTypeOfX);
this.map = map;
}
#Override
public void load(S s)
{
for (A<? extends S> a : map.values())
{
if (a.typeOfX.isAssignableFrom(s.getClass()))
{
callLoad(a, s);
}
}
}
private static <S, T extends S> T cast(A<T> a, S s)
{
T t = a.typeOfX.cast(s);
return t;
}
private static <T, S extends T> void callLoad(A<S> a, T s)
{
a.load(cast(a, s));
}
}
I would not recommend this in practice.
Personally and subjectively: I think that when you are doing the isAssignableFrom check, then the (unchecked) cast should be as close as possible to this check. Otherwise, the code will be very hard to understand.
So although unchecked casts are a code smell in practice, and I try to avoid SuppressWarning whenever possible, I would consider this as far more readable:
for (A<? extends S> a : map.values())
{
if (a.typeOfX.isAssignableFrom(superx.getClass()))
{
// This call is safe as of the check done above:
#SuppressWarnings("unchecked")
A<Object> castA = (A<Object>) a;
castA.load(superx);
}
}

Generic Type as generic type parameter

I want to know if I can improve my class, by avoiding the second V in the declaration of my class. Somehow it looks awful.
public abstract class TreeElementAction<T extends TreeNode<V>, V> {
protected abstract boolean actFor(#Nullable T element);
public void forEachElementInTree(#Nonnull T rootNode) {
requireNonNull(rootNode);
actFor(rootNode);
Collection<T> children = (Collection<T>) rootNode.getChildren();
for (T treeNode : children) {
forEachElementInTree(treeNode);
}
}
}
Unless you require V in any of the concrete implementations of this class, you can just drop the type variable, as #PeterLawrey has suggested, and replace it with an unbounded wildcard in TreeNode<V>:
public abstract class TreeElementAction<T extends TreeNode<?>> {

How to replace a parameterized type with a more specific one

Consider the following setup:
We have an interface SuperType which is parameterized like this:
public interface SuperType<V> {
}
SuperType supports method chaining. Hence it defines another type parameter which captures the concrete implementing subtype returned by each method like this:
public interface SuperType<V, S extends SuperType<V, S>> {
public S doSomething();
}
Let's consider an implementation of SuperType<V, S extends SuperType<V, S>>:
public class SubType<V> implements SuperType<V, SubType<V>> {
private final V value;
public SubType(V value) { this.value = value; }
public SubType<V> doSomething() { return this; }
}
Someone instantiates SubType<V> using for example strings but provides Object for the type parameter V:
Object s = "Java Generics";
SubType<Object> x = new SubType<>(s);
Now we want to define another method for SuperType<V, S extends SuperType<V, S>> which takes a more specific type parameter of V and returns the same implementation type S but now parameterized with W extends V:
public interface SuperType<V, S extends SuperType<V, S>> {
public S doSomething();
public <W extends V, T extends SuperType<W, T>> T doMoreSpecific(Class<W> typeToken);
}
This new interface definition is intended to support:
Object s = "Java Generics";
SubType<Object> x = new SubType<>(s);
SubType<String> y = x.doMoreSpecific(String.class);
Here I struggle to implement SubType<V>. What I want to provide as an implementation is:
public class SubType<V> implements SuperType<V, SubType<V>> {
private final V value;
public SubType(V value) { this.value = value; }
public SubType<V> doSomething() { return this; };
public <W extends V> SubType<W> doMoreSpecific(Class<W> typeToken) {
return new SubType<>((W) value);
}
}
My Question is:
How should I define the signature for the method doMoreSpecific() in the type SuperType<V, S extends SuperType<V, S>> so that the implementation provided by
SubType<V> implements SuperType<V, SubType<V>> is acceptable?
Or otherwise, which implementation and interface method definition would do the trick?
Or else, why can't we do this in Java?
Using the following signature:
<W extends V> SuperType<W, ?> doMoreSpecific(Class<W> typeToken);
There might be some unsafe cases though that I have not been able to find yet, any criticism is welcome!
You can't do what your code suggests you want, you have a typed method: W is inferred from the parameter type, but the parameter type is known only at the call site. ie there isn't one version of the method doMoreSpecific() that can be specified in the interface SuperType (that must be implemented).
The closest you could get is to make W a generic type parameter of SuperType, but then your implementation would work for exactly one class W, which would be the typeToken redundant, which is clearly not what you want.
I don't know what your exact intention is behind doMoreSpecific, but if it is just casting from SubType<Object> to SubType<String> you could do the following (although this is not very good practice...):
Object s = "Java Generics";
SubType<Object> x = new SubType<>(s);
SubType<String> y = (SubType<String>) (SubType<?>) x;
Note 1: This will still give a Warning.
Note 2: This cast will even work if s is not of Type String! But you will then get a ClassCastException when calling y.doSomething(). (Which you would get in your example for that case, too).
For example: The following piece of (ugly) code would work, too (except for the lines highlighted):
ArrayList<?> lo = new ArrayList<Object>();
ArrayList<Integer> li = (ArrayList<Integer>) lo;
ArrayList<String> ls = (ArrayList<String>) lo;
li.add(5);
ls.add("five");
System.out.println(lo); // prints "[5, five]"
System.out.println(li.get(0)); // prints "5"
System.out.println(li.get(1)); // ClassCastException
System.out.println(ls.get(0)); // ClassCastException
System.out.println(ls.get(1)); // prints "five"
Note 3: This perfectly shows how generics in fact work: All they do is automatically insert casts at the required positions for you.

Categories

Resources