public abstract class OuterClass<OT extends OuterClass<OT>> {
public <C extends OuterClass<?>> C parse(Class<C> clazz) {
if (clazz.isInstance(this)) {
return (C) this;
}
return null;
}
public abstract class InnerClass<CT extends InnerClass<CT> {
public <C extends InnerClass<?>> C parse(Class<C> clazz) {
if (clazz.isInstance(this)) {
return (C) this;
}
return null;
}
}
}
OuterClass<?> oInstance;
InnerClass<?> iInstance;
In the above example the iInstance
variable works fine. However the iInstance
variable shows an error when adding the generics part
Type arguments given on a raw type
If I remove the generics part from variables, then the below test cases will fail with type errors
public class ExtendedOuter extends OuterClass<ExtendedOuter> {
}
// This only works on OuterClass<?> and not on OuterClass
ExtendedOuter eInstance = oInstance.parse(ExtendedOuter.class);
Found: OuterClass, required: ExtendedOuter
This is no problem on static/outer classes as they can be defined as ClassName<?>
, but non-static inner classes cannot be defined with <?>
How can I add <?>
to iInstance
without making InnerClass
static?
EDIT: Let me give some examples why these classes uses their extended versions as generic.
public abstract class OuterClass<OT extends OuterClass<OT>> {
public abstract OT returnMe();
}
public class ExtendedOuter extends OuterClass<ExtendedOuter> {
@Override
public ExtendedOuter returnMe() {
return this;
}
}
The above for an example would not work if I simply made the return type OuterClass
on the abstract version. If so, any extended versions would have to be casted whenever this method was used, which does not seam ideal.
Also just got an error from AndroidStudio as well after removing <CT>
in <T extends OuterClass<CT>>
The parameter OT is not within it's bound
This error is shown in extended classes when doing ClassName extends OuterClass<ClassName>
. In other words it will not work just using <T extends OuterClass>
on the abstract classes.
Similar to a previous post I did which showcased a builder patter which uses generic types and inheritance to reduce the actual code in inheritance cases, this is also possible for none-static classes. I therefore modified the builder example accordingly to avoid static inner-classes:
Parent class with parent builder:
public abstract class TestParam<Z>
{
public abstract class CommonBuilder<T extends CommonBuilder<T>>
{
protected final String a;
protected final String b;
protected final String c;
protected Z z = null;
public CommonBuilder(String a, String b, String c)
{
this.a = a;
this.b = b;
this.c = c;
}
@SuppressWarnings("unchecked")
public T withOptionalZ(Z z)
{
this.z = z;
return (T)this;
}
@SuppressWarnings("hiding")
public abstract <T> T build();
}
protected String name;
protected String a;
protected String b;
protected String c;
protected Z z = null;
protected TestParam() {
}
protected TestParam(String name, String a, String b, String c)
{
this.name = name;
this.a = a;
this.b = b;
this.c = c;
}
protected TestParam(String name, String a, String b, String c, Z z)
{
this.name = name;
this.a = a;
this.b = b;
this.c = c;
this.z = z;
}
public String getA()
{
return a;
}
public String getB()
{
return b;
}
public String getC()
{
return c;
}
protected abstract String getContent();
@Override
public String toString()
{
return name+"[A: " + a + ", B: " + b + ", C: " + c + (z != null ? ", Z: " + z.toString() : "") + getContent() +"]";
}
}
A child class with a none-static builder looks like this:
@SuppressWarnings({"hiding", "unchecked"})
public class TestParamA<D,E,Z> extends TestParam<Z>
{
public class Builder<T extends TestParamA<D,E,Z>,
B extends TestParamA<D,E,Z>.Builder<? extends TestParamA<D,E,Z>, ? extends B, D, E>,
D,E>
extends TestParam<Z>.CommonBuilder<Builder<TestParamA<D,E,Z>,B, D,E>>
{
protected D d;
protected E e;
public Builder(String a, String b, String c)
{
super(a, b, c);
}
public B withD(D d)
{
this.d = d;
return (B)this;
}
public B withE(E e)
{
this.e = e;
return (B)this;
}
@Override
public <T> T build()
{
TestParamA<D,E,Z> t = new TestParamA<>("TestParamA", a, b, c, z, d, e);
return (T)t;
}
}
protected D d;
protected E e;
public TestParamA() {
super();
}
protected TestParamA(String name, String a, String b, String c, Z z, D d, E e)
{
super(name, a, b, c, z);
this.d = d;
this.e = e;
}
public D getD()
{
return d;
}
public E getE()
{
return e;
}
@Override
protected String getContent()
{
return ", D: " + d + ", E: " + e;
}
}
To test the functionality of this outer/inner classes you can implement something like this:
public class Main
{
public static void main(String ... args)
{
TestParamA<D,E,String> a = new TestParamA<>().new Builder<>("a","b","c").withD(new D()).withE(new E()).build();
TestParamB<F,G,String> b = new TestParamB<>().new Builder<>("a","b","c").withF(new F()).withG(new G()).withOptionalZ("z").build();
TestParam<String> c = new TestParamA<>().new Builder<>("a","b","c").withD(new D()).withE(new E()).withOptionalZ("z").build();
TestParam<?> d = new TestParamB<>().new Builder<>("a","b","c").withF(new F()).withG(new G()).build();
test(a);
test(b);
test(c);
test(d);
TestParam<?>.CommonBuilder<? extends TestParam<?>.CommonBuilder<?>> builder =
new TestParamA<>().new Builder<>("a", "b", "c").withD(new D()).withE(new E());
test(builder);
// or a bit shorter
TestParam<?>.CommonBuilder<?> builder2 =
new TestParamB<>().new Builder<>("a", "b", "c").withF(new F()).withG(new G());
test(builder2);
}
public static void test(TestParamA<?,?,?> testParam)
{
System.out.println("Test for ParamA: " + testParam.toString());
}
public static void test(TestParamB<?,?,?> testParam)
{
System.out.println("Test for ParamB: " + testParam.toString());
}
public static void test(TestParam<?> testParam)
{
System.out.println("Test for Param: " + testParam.toString());
}
public static void test(TestParam<?>.CommonBuilder<?> builder)
{
System.out.println("Test for CommonBuilder: " + builder.build().toString());
}
}
TestParamB
is identical to TestParamA
- it only contains varialbe and builder-methods for F
and G
instead of D
and E
. Furthermore, D
, E
, F
and G
are only classes with a simple toString()
implementation which returns just the simple classname.
This will print the following output:
Test for ParamA: TestParamA[A: a, B: b, C: c, D: D, E: E]
Test for ParamB: TestParamB[A: a, B: b, C: c, Z: z, F: F, G: G]
Test for Param: TestParamA[A: a, B: b, C: c, Z: z, D: D, E: E]
Test for Param: TestParamB[A: a, B: b, C: c, F: F, G: G]
Test for CommonBuilder: TestParamA[A: a, B: b, C: c, D: D, E: E]
Test for CommonBuilder: TestParamB[A: a, B: b, C: c, F: F, G: G]
However the iInstance variable shows an error when adding the generics part
Type arguments given on a raw type
First of all, that's not the problem you should be getting, because InnerClass
is not defined in the scope. Being an inner class, it is scoped inside the outer class's scope. So when it is outside the outer class, you need to explicitly qualify it with an outer class, or it will give you a InnerClass
symbol not found error. So you are not showing your real code (maybe you have another InnerClass
somewhere) or not show your real error.
If I remove the generics part from variables, then the below test cases will fail with type errors
When you use a raw type to access members, that turns off all generics on those members. So .parse()
is erased to public OuterClass parse(Class clazz)
(this is true even though CT
is not used by the method), and that's why oInstance.parse(ExtendedOuter.class)
returns type OuterClass
which is not compatible with ExtendedOuter
.
How can I add
<?>
to iInstance without making InnerClass static?
Like OuterClass<?>.InnerClass<?>
, or OuterClass<Something>.InnerClass<SomethingElse>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.