Rooboo
Rooboo

Reputation: 253

Nested Generics

I got several classes:

Standard classes:

WorkflowGraphModel:

public class WorkflowGraphModel<T> implements IWorkflowGraphModel<T>

public WorkflowGraphModel( List<IWorkflowGraphEntry<T>> entries ) 
{
  this.entries = entries;
}

WorkflowGraphEntry:

public class WorkflowGraphEntry<T> implements IWorkflowGraphEntry<T>

Special implementations:

ApprovalStepGraphEntry

public class ApprovalStepGraphEntry extends WorkflowGraphEntry<ApprovalStep>

ApprovalStepGraphModel

public class ApprovalStepGraphModel extends WorkflowGraphModel<ApprovalStepGraphEntry>

public ApprovalStepGraphModel( List<ApprovalStepGraphEntry> stepEntries )
{
  super( stepEntries );
}

There is an error when calling

super( stepEntries );

WorkflowGraphModel (java.util.List>) in WorkflowGraphModel cannot be applied to (java.util.List)

I don't know why the compiler doesn't know that ApprovalStepGraphEntry implements IWorkflowGraphEntry. In my opinion the generics are well set.

Upvotes: 0

Views: 157

Answers (2)

pushy
pushy

Reputation: 9635

Your ApprovalStepGraphEntry does not implement IWorkflowGraphEntry, it extends WorkflowGraphEntry, which in turn implements the interface. You need to make this distinction clear when defining the generic type:

Instead of

public WorkflowGraphModel( List<IWorkflowGraphEntry<T>> entries )

You need

public WorkflowGraphModel( List<? extends IWorkflowGraphEntry<T>> entries )

Upvotes: 0

Mikhail Vladimirov
Mikhail Vladimirov

Reputation: 13890

Type List <IWorkflowGraphEntry <ApprovalStep>> is not assignable from List <ApprovalStepGraphEntry>. You should probably change List <IWorkflowGraphEntry <ApprovalStep>> to List<? extends IWorkflowGraphEntry <ApprovalStep>> or something like this.

Here is an explanation why types mentioned above are not compatible. Lets consider we have:

interface A {...}
class B extends A {...}
class B1 extends A {...}
interface C <T> {public void set (T t);}

Then the following is incorrect:

C <A> ca;
C <B> cb = ...;
ca = cb; // Error here
ca.set (new B1 ()); // Correct!

Note that once ca is declared as C <A> ca, method ca.set accepts parameter of type A thus new B1() is valid value for it. At the same time, method cb.set accepts parameter of type B, and thus new B1() is not a valid value for this parameter. If we would be able to assign cb to ca, then we would be able to later call ca.set (new B1()) which will pass value of invalid type to the set method. To prevent such situations, compiler treats C <A> and C <B> types as incompatible even when A and B are compatible.

Upvotes: 1

Related Questions