-2

There is a trick to make inter-class circular reference within Java generics:

public static class GenA<A extends GenA<A, B>, B extends GenB<A, B>> {
    public B objB;
}
public static class GenB<A extends GenA<A, B>, B extends GenB<A, B>> {
    public A objA;
}

When I try to instantiate real object:

GenA<GenA, GenB> genA = new GenA<>();

I get compilation errors:

CircularRef.java:7: error: type argument GenA is not within bounds of type-variable A
        GenA<GenA, GenB> genA = new GenA<>();
  where A,B are type-variables:
    A extends GenA<A,B> declared in class GenA
    B extends GenB<A,B> declared in class GenA
CircularRef.java:7: warning: [rawtypes] found raw type: GenA
        GenA<GenA, GenB> genA = new GenA<>();
  missing type arguments for generic class GenA<A,B>
  where A,B are type-variables:
    A extends GenA<A,B> declared in class GenA
    B extends GenB<A,B> declared in class GenA
CircularRef.java:7: warning: [rawtypes] found raw type: GenB
        GenA<GenA, GenB> genA = new GenA<>();
  missing type arguments for generic class GenB<A,B>
  where A,B are type-variables:
    A extends GenA<A,B> declared in class GenB
    B extends GenB<A,B> declared in class GenB
CircularRef.java:7: warning: [unchecked] unchecked method invocation: constructor <init> in class GenA is applied to given types
        GenA<GenA, GenB> genA = new GenA<>();
  required: no arguments
  found: no arguments
CircularRef.java:7: warning: [unchecked] unchecked conversion
        GenA<GenA, GenB> genA = new GenA<>();
  required: GenA<GenA,GenB>
  found:    GenA

I know workaround:

public static class AdapterA extends GenA<AdapterA, AdapterB> { } 
public static class AdapterB extends GenB<AdapterA, AdapterB> { } 

which works like:

AdapterA adA = new AdapterA();
AdapterB adB = new AdapterB();
adA.objB = adB;
adB.objA = adA;

How can I instantiate GenA / GenB classes directly?

They are not abstract. I like -Xlint:all says no warning too.

EXTRA I wrote question Defining typed hierarchy with Java generics and type self-referencing which contains above problem hidden in a lot of code and bored users like to close it ))

Some hints about declaring generic circular referencing declaration are at:

UPDATE With adding extra reference:

public static class GenA<A extends GenA<A, B, C>, B extends GenB<A, B, C>, C extends GenC<A, B, C>> {
    public B objB;
    public C objC;
}
public static class GenB<A extends GenA<A, B, C>, B extends GenB<A, B, C>, C extends GenC<A, B, C>> {
    public A objA;
    public C objC;
}
public static class GenC<A extends GenA<A, B, C>, B extends GenB<A, B, C>, C extends GenC<A, B, C>> {
    public A objA;
    public B objB;
}

problem the same for:

GenA<GenA, GenB, GenC> genA = new GenA<>();

and can be resolved as usual:

public static class AdapterA extends GenA<AdapterA, AdapterB, AdapterC> { } 
public static class AdapterB extends GenB<AdapterA, AdapterB, AdapterC> { } 
public static class AdapterC extends GenC<AdapterA, AdapterB, AdapterC> { } 

UPDATE 2 The problem is not with instantiation but with declaration of type, following fails:

GenA<GenA, GenB> genA;
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • You might not be able to: `GenA genA = new GenA<>();` should be `GenA, GenB<...>>, GenB, GenB<...>>> genA = new GenA<>();`, which may end up being infinitely long. – Mad Physicist Dec 30 '17 at 13:32
  • **@MadPhysicist** I thought about this but was not sure as I am not experienced with Java Generic spec... – gavenkoa Dec 30 '17 at 13:33
  • What happens if you add just one more level of nested generics there? Will it get rid of the raw type error? It'll be better than having an adapter class if it works. – Mad Physicist Dec 30 '17 at 13:34
  • **@MadPhysicist** The same. See updates to question. – gavenkoa Dec 30 '17 at 13:40
  • Yup: https://ideone.com/8EGuTo – Mad Physicist Dec 30 '17 at 13:41
  • I suspect there's no shortcut then. – Mad Physicist Dec 30 '17 at 13:43
  • updated the IDEOne link with another idea. Didn't work either. – Mad Physicist Dec 30 '17 at 13:49
  • 4
    Do you have an actual use case for this? Thinking about it, I can't imagine a case where this would be useful in any way that wasn't fully covered but plain old runtime polymorphism. – Mad Physicist Dec 30 '17 at 13:51
  • @MadPhysicist I put a reference to original question, look into UPDATE. Actually it is happen frequently when parent stores set of children and *children have link to parent*. But actual declaration become more complicated to investigate problem. – gavenkoa Dec 30 '17 at 14:13

1 Answers1

2

You can instantiate in a method with its own type variables:

<A extends GenA<A, B>, B extends GenB<A, B>> GenA<A, B> thing() {
  return new GenA<>();
}

Of course, this is merely punting the question of "how do I instantiate it" to "how do I invoke this method". And the answer to that is to invoke it in a method with its own type variables (or use GenA<?, ?> as the type receiving the value).

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • Yeah, both `GenA a = thing<>();` and `GenA, ?> a = thing<>();` produces errors... Also `AdapterA xA = thing();` produces error – gavenkoa Dec 30 '17 at 14:40
  • Probably because `thing<>()` isn't valid syntax. For one thing, type hints to methods come before the method name; for another, diamond operator is only applicable to the new operator. – Andy Turner Dec 30 '17 at 14:42