Java circular Generics - java

I'm having a problem understanding Java generics and I've simplified to this example
class A<T extends B> {
public void fun(T t) {
}
}
class B {
A a;
public void event() {
a.fun(this);
}
}
The problem is that this generates a warning because A is defined inside B but A is already using it as a generic type.
My first instinct would be that my design is wrong, but in this case I can't change it. A is like a collection and B is like a node in the collection that users are supposed to override. Certain events can happen in B that require reporting back to the parent A.
But since A is defined generically with B, how do I avoid the compile warning inside B.event()
Thanks

The problem is that you're using a raw type on this line:
A a;
You need to specify a type for A's type parameter (T).
You could do something like this:
A<B> a;
but then A might as well not be generic at all, if I'm understanding your statement of the problem. You probably want to do something like this:
class A<T> {
public void fun(T t) {
}
}
class B<T extends B<T>> {
A<B<T>> a;
public void event() {
a.fun(this);
}
}
or even this:
class A<T extends B<? extends T>> {
public void fun(T t) {
}
}
class B<T extends B<T>> {
A<? super B<T>> a;
public void event() {
a.fun(this);
}
}
There are a couple of variations in-between these that are possibly useful as well. The latter example is the most generic (but obviously, also the most complicated).
The class A<T extends B<? extends T>> is ensuring that the type parameter to A is a B. Since B is itself generic, and has that cyclic type parameter, you end up needing to say B<? extends T> (simply saying T won't work here).
The class B<T extends B<T>> is as close as you can get to emulating a "self type" in Java. This lets B talk about the (almost) concrete subtype of itself. When subclassing B you'd say something like "class C extends <B<C>>". This is useful because now the type of C.a is actually A<? super B<C>>.
The ? super bit in the latter example is only useful if you plan on connecting a B with an A that isn't for exactly the same type of B. Thinking in concrete terms, suppose you had an A<Shape> and a Circle (which extends Shape which extends B). The super-wildcard lets you use them together. Without it you'd need an A<Circle> rather than an A<Shape> for your Circle.

Code
public class A<T extends B> {
public void fun(T t) {
}
}
public class B {
A<B> a;
public void event() {
a.fun(this);
}
}
The warning is vanquished.
Reason
Variables of type A should be declared using a specific class type, as suggested by the generic class signature (A<T extends B>).
Resolution
While this resolves the compiler warning, the underlying problem remains. Laurence provides an excellent explanation and solution to the core issue.

Related

How to ensure this is the generic type referenced in my class signature?

Suppose we have three classes - AbstractMessage, AbstractEngine, and AbstractAction. These three classes all reference each other in a generic fashion so each Engine has a corresponding message and action and you can refer to them directly in the code.
public class MyMessage<M extends AbstractMessage<M,E,A>, E extends AbstractEngine<M,E,A>, A extends AbstractAction<M,E,A>> {
This is working fine, but when I attempt to enforce behavior at the highest level I run into some problems. My AbstractAction class has an applyTo method defined thusly:
protected abstract M applyTo(E engine, Object guarantee);
and my AbstractEngine class has this
private final M apply(A action) {
return action.apply(this, this.guarantee);
}
And it is on this line that it balks - complaining that:
The method applyTo(E, Object) in the type AbstractAction<M,E,A> is not
applicable for the arguments (AbstractEngine<M,E,A>, Object)
Now the reason for this is clear - the E in question might be some OTHER AbstractEngine and there's no way to know if the subclass we're calling this from is actually an E.
My question is, how can I say for certainty that if you're going to class MyEngine extends AbstractEngine<M...,E...,A...> that MyEngine is MUST be an E? And to have this certainty baked into AbstractEngine?
Here is a small example that illustrates the problem.
class EngineExample {
static abstract class AbEng<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
final M func(A act) {
return act.apply(this); // compile error here
}
}
static abstract class AbMes<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
}
static abstract class AbAct<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
abstract void apply(E e);
}
static class RealEng extends AbEng<RealAct, RealMes, RealEng> {
}
static class RealMes extends AbMes<RealAct, RealMes, RealEng> {
}
static class RealAct extends AbAct<RealAct, RealMes, RealEng> {
void apply(RealEng eng) {
System.out.println("applied!");
}
}
}
Use loosest valid parameter type
The simplest solution, is to not actually enforce that this isInstanceOf E. The rules of abstraction already guarantee that this is a safe operation, so it will just work if you change the parameter to just allow any Engine.
abstract Action<E> {
public void apply(Engine<?> e, Object o) {
e.doSomething(o);
}
}
or
abstract Action<E> {
<T extends Engine<?>> public T apply(T e, Object o) {
return e.doSomething(o);
}
}
Use a type-safe wrapper
Another solution is to create another class that binds these 3 together, and move the interaction calls to the wrapper.
abstract System<A extends Action, M extends Message, E extends Engine> {
abstract void apply(A action, E engine) {
engine.render(action.apply())
}
}
Or have the wrapper class take an instance of these 3 and use the passed in versions. This basically is the "allow anything close enough" solution, and adding another class to manage how they can and can't talk to each other.
Pre-cast check
You can also make a reference cast on construction to throw an error if the cast setup is invalid.
private final E dis = (E) this;
This really just moves the problem from from always on compile time, to sometimes on run time, so in general, not a safe/stable solution.
This next solution is a bit specific to your case (using info from our discussion). Basically, you want to define a method in an abstract class that class A and B can inherit, but A and B should not be interchangeable using their base class.
Just use polymophism and use generics just as a type segregator
Here is a modification of the MVCe that uses polymorphism instead, using generics only as a kind of type-category-exclusive-locking mechanism. Basically, Type is a semantic interface to say whether semantically, it makes sense for these classes to talk to each other. (A Physics Engine and Light Engine may share some functionality, but it would make no sense to let them be interchangeable.)
class test {
public static void main(String[] rawrs) {
RealEng re = new RealEng();
RealAct ra = new RealAct();
MockAct ma = new MockAct();
ra.apply(re);
// Remove all code related to Type interface if next line should compile
ma.apply(re); // compile error here
}
static interface Type {
}
static interface Real extends Type {
};
static interface Mock extends Type {
};
static abstract class AbEng<T extends Type> {
final void func(AbAct<T> act) {
act.apply(this); // compile error here
}
}
static abstract class AbMes<T extends Type> {
}
static abstract class AbAct<T extends Type> {
abstract void apply(AbEng<T> e);
}
static class RealEng extends AbEng<Real> {
}
static class RealMes extends AbMes<Real> {
}
static class RealAct extends AbAct<Real> {
#Override
void apply(AbEng<Real> eng) {
System.out.println("applied!");
}
}
static class MockAct extends AbAct<Mock> {
#Override
void apply(AbEng<Mock> eng) {
System.out.println("applied!");
}
}
}
Recursive type-parameters in Java generics are often troublesome.
The problem here is that paradoxically there in no way that you can guaranteed that this makes reference to an instance of E; the only thing that we known about this is that it also extends Engine<M, A, E> but not that is actually E.
Obvious solution is to add a cast ((E)this) and that might be an acceptable solution but you must make clear in the contract (thru javadoc or other documentations) that Engine extending classes must assign E to themselves.
Another solution simply change those method signatures to be a bit more flexible and instead E accept any engine that extends Engine<M, A, E>.
protected abstract M applyTo(AbstractEngine<M, A, E> engine, Object guarantee);
Also consider to reduce the number of type-parameters whenever possible. For example does Engine need to make reference to its own type? Does it have any method that accepts or returns and engine that must be of the same type/class?
EDIT
If you want to keep the E type parameter in applyTo another option is to create a field typed E in AbstractEngine that would be the one passed to the apply to. This field in fact would make reference to this but once it has been "casted" safely at construction.:
public class AbstractEngine<M extends ..., A extends ..., E extends ...> {
private final E engine;
protected AbstractEngine(final E engine) {
this.engine = Objects.requiresNonNull(engine);
}
}
public class MyEngine extends AbstractEngine<MyMessage, MyAction, MyEngine> {
public MyEngine() {
super(this);
}
}
The reason this works is that when we are declaring MyEngine then the compiler does know that MyEngine is E and so the "cast" is safe one. Then the code in AbstractEngine can use the casted value safely thereafter.
The obvious inconvenience is the extra field making reference to this, that although is a bit of memory waste in practice is probably negligible.
Here we are adding the possibility that an engine could designate a surrogate engine to be used in their apply method calls. Perhaps that might be useful... but if you really want to make it impossible to use a third engine here, then you can change the code in the AbstractEngine constructor to compare the passed engine with this and fail at runtime if they are not the same.
protected AbstractEngine(final E engine) {
if (engine != this) {
throw new IllegalArgumentException();
}
this.engine = engine;
}
Unfortunately this cannot be check at compilation time... the second best thing you can do is to make it part of your code tests to verify that all AbstractEngine extending classes are compliant so it would fail at build-time.

Can I get a collection of object extending a class and implementing an interface?

There's not much to add to my question, basically:
class A {}
interface I {}
// how can I get a Set<> of object of type A that implements I?
I tried a few things <A & I>, <A extends I>, <? super A extends I> and a few other but didn't find anything that works, so I'm wondering if this is possible at all. If it isn't I'm curious about the reasoning behind it.
Thanks
Java does not support intersection types, it only supports multiple bounds (as in extends A & I) when declaring type parameters. That is, we can not use a notation like A & I to denote the family of types that extend both A and I, but we can declare a type parameter <T extends A & I> to refer to a specific such type.
If the latter is what you want, a type parameter is a great fit. But if your collection should admit unrelated subtypes of A and I, no nice solutions seem to exist. My best idea is a hack like:
class AISetWrapper {
Set<A> set = new HashSet<>();
<T extends A & I> Set<T> getSet() {
return (Set<T>) set; // unchecked cast that only works because generics are not reified
}
}
which would allow us to write:
class AI1 extends A implements I { }
class AI2 extends A implements I { }
public static void main(String[] args) {
AISetWrapper aiSet = new AISetWrapper();
aiSet.get().add(new AI1()); // compiles
aiSet.get().add(new AI2()); // compiles
aiSet.get().add(new A()); // does not compile
aiSet.get().add(new I() {}); // does not compile
}
You'll have to make A implement I:
interface I {}
class A implements I {}
Set<A> setOfA;
Possible is alsp
class SubA extends A implements I { }
Set <SubA> setOfSubA;
Usage of a class A cannot make it change it's behaviour, as would be indicated by its sudden "implmentation" of I. Where should the implementations of the interface methods come from?
I was able to do the following:
public class MyClass<T extends String & Iterable>{
private Set<T> mySet;
}
And
public <T extends String & Iterable> void myFancyMethod(Set<T> mySet){}
However when I did
private Set<? extends String & Iterable>
I got a compile error of Syntax error on token "&". Seems that you can do the & syntax when declaring a type <T> but not for wildcards <? ...>.
A better discussion of this can be found at: Java Generics Wildcarding With Multiple Classes
You can write your own class:
public class MySet<E extends A & I> extends HashSet<E> {
// blank
}
This will simply ensure that any instances of MySet will contain only objects that extend A and implement I.
// how can I get a Set<> of object of type A that implements I?
You cannot guarantee both in a single generic statement. You can do something like
public void addToSet(I iInstance) {
if(iInstance instanceof A){
//logic to add to your set
}
}

Wrapper hierarchies with Java generics

Is there any way using Java generics to express a type hierarchy like the following?
class A { ... }
class B extends A { ... }
interface Wraps<T> {
T getWrapped();
}
class WrapsA implements Wraps<A> {
A getWrapped();
}
class WrapsB extends WrapsA /* implements Wraps<B> */ {
B getWrapped();
}
I understand that as written Java's type system will reject this code, but is there any way I can specify the type parameters or inheritance hierarchy that will get this working?
EDIT: I realized that the real issue I'm having is I'm trying to enforce type safety in my API for a method like
<T extends A> T unwrap(Wraps<T> wrapper, Class<T> wrappedClass);
I'm not able to call it with unwrap(wrapsB, B.class). Is this something that Java will handle?
You can just use
class WrapsB extends WrapsA {
B getWrapped();
}
Since you're allowed to return subclasses in overriden methods (it's possible from Java SE6, as far as I remember)
Check out self-bounded types.
interface Wraps<T, W extends Wraps<T, W>> { ... }
abstract class AbstractWrapsA< T extends A, W extends AbstractWrapsA< T, W > implements Wraps< T, W > { ... }
class WrapsA extends AbstractWrapsA< A, WrapsA > {}
class WrapsB extends AbstractWrapsA< B, WrapsB > { ... }
EDIT: Actually to satisfy the OP's need we can dispense with self-bounded types and just migrate the guts of WrapsA to an abstract class. We still do not have that WrapsB both is-a WrapsA and is-a Wraps<B>.

in Java syntax, Class<? extends Something>

Class<? extends Something>
Here's my interpretation, it's class template but the class ? means the name of the class is undetermined and it extends the Something class.
if there's something wrong with my interpretation, let me know.
There are a few confusing answers here so I will try and clear this up.
You define a generic as such:
public class Foo<T> {
private T t;
public void setValue(T t) {
this.t = t;
}
public T getValue() {
return t;
}
}
If you want a generic on Foo to always extend a class Bar you would declare it as such:
public class Foo<T extends Bar> {
private T t;
public void setValue(T t) {
this.t = t;
}
public T getValue() {
return t;
}
}
The ? is used when you declare a variable.
Foo<? extends Bar>foo = getFoo();
OR
DoSomething(List<? extends Bar> listOfBarObjects) {
//internals
}
You are almost right.
Basically, Java has no concept of templates (C++ has).
This is called generics.
And this defines a generic class Class<> with the generics' attribute being any subclass of Something.
I suggest reading up "What are the differences between “generic” types in C++ and Java?" if you want to get the difference between templates and generics.
You're right
Definition is that the class has to be subtype of Something
It's the same as Class<T>, but there is a condition that T must extends Something
Or implements Something as Anthony Accioly suggested
It can also be class Something itself
You're correct.
In Java generics, the ? operator means "any class". The extends keyword may be used to qualify that to "any class which extends/implements Something (or is Something).
Thus you have "the Class of some class, but that class must be or extend/implement Something".
You're correct.
However usually you will want to name the class that extends Something and write e.g. <E extends Something>. If you use ? you can't do anything with the given type later.

Can't compile class calling a method in an interface with a generic list argument

Just got a question about generics, why doesn't this compile when using a generic List? If its not possible, anyway around it? Much appreciate any answer.
// Interface used in the ServiceAsync inteface.
public interface BaseObject
{
public String getId();
}
// Class that implements the interface
public class _ModelDto implements BaseObject, IsSerializable
{
protected String id;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
}
// Interface used in the ServiceAsync inteface.
public interface MyAsync<T>
{
// Nothing here.
}
// Service interface use both interfaces above.
public interface ServiceAsync
{
public void getList(MyAsync<List<? extends BaseObject>> callback);
}
public class MyClass
{
ServiceAsync service = (some implementation);
MyAsync<List<_ModelDto>> callBack = new MyAsync<List<_ModelDto>>()
{
};
service.getList(callBack); // This does not compile, says arguments are not applicable????
}
The fact that your MyAsync interface doesn't contain any method signatures and doesn't have a particularly informative name is a code smell from my perspective, but I'll assume that this is just a dummy example. As it is written, getList() couldn't ever have any reasonable implementation that used the callback in any way; remember that type erasure will erase this method signature to getList(MyAsync callback);
The reason that this doesn't compile is that your bound is wrong. MyAsync<List<? extends BaseObject>> gives T as List<? extends BaseObject>, a list of some unknown type.
It looks to me like what you want is for the getList method itself to be generic:
public interface ServiceAsync {
public <T extends BaseObject> void getList(MyAsync<List<T>> callback);
}
public class MyClass {
public void foo() {
ServiceAsync service = null;
MyAsync<List<_ModelDto>> callBack = new MyAsync<List<_ModelDto>>() {};
service.getList (callBack); // This compiles
}
}
The '?' in generic types can be pretty confusing. Honestly I'm not sure why this won't compile. It has to do with using the '?' in a nested generic type. But I do know some ways to work around it.
Is there a reason that the declaration of the MyAsync in MyClass has to reference _ModelDto? It would work if you changed it to look like this:
ServiceAsync service = (some implementation);
MyAsync<List<? extends BaseObject>> callBack = new MyAsync<List<? extends BaseObject>>()
{
};
service.getList(callBack);
If you need to reference the type _ModelDto directly you could change the definition of ServiceAsync and it will fix the problem.
Change it to look like this:
public interface ServiceAsync<T extends BaseObject>
{
public void getList(MyAsync<List<T>> callback);
}
Then add the parameter type to the declaration in MyClass
public class MyClass
{
public void method()
{
ServiceAsync<_ModelDto> service = (some implementation);
MyAsync<List<_ModelDto>> callBack = new MyAsync<List<_ModelDto>>()
{
};
service.getList(callBack);
}
}
This has got to do with the subtyping rules for parametrized types. I'll explain it in three steps:
Non-nested case
When you have the following subtype relation (where <: is the symbol for "is a subtype of"):
_ModelDto <: BaseObject
The following relation does not hold:
List<_ModelDto> <: List<BaseObject>
But the following relations do:
List<_ModelDto> <: List<? extends _ModelDto> <: List<? extends BaseObject>
This is the reason why Java has wildcards: to enable these kind of subtype relations. All of this is explained in the Generics tutorial. If you understand this, we can continue with the nested case...
Nested case
Let's do exactly the same, but with one more level of nesting. Starting from the subtype relation:
List<_ModelDto> <: List<? extends BaseObject>
The following relation does not hold, for exactly the same reasons as above:
MyAsync<List<_ModelDto>> <: MyAsync<List<? extends BaseObject>>
This is precisely the conversion you are trying to do when calling service.getList(callBack), and since the subtype relation does not hold, the conversion fails.
However, as above, you do have the following relations:
MyAsync<List<_ModelDto>>
<: MyAsync<? extends List<_ModelDto>>
<: MyAsync<? extends List<? extends BaseObject>>
Solution
So you should write the signature of getList as follows to make the call work:
public void getList(MyAsync<? extends List<? extends BaseObject>> callback);
The difference will be that the body of getList will be constrained with how it can use the callback. If MyAsync contains the following members:
public interface MyAsync<T> {
T get();
void set(T t);
}
Then, the body of getList will be able to get a list from the callback. However, it cannot set the list (except setting it to null), because it does not know exactly what kind of list is represented by the ?.
In contrast, with your original signature, set is available, and that is why the compiler cannot allow your argument.

Categories