在非静态内部类中使用泛型

时间:2015-07-07 17:29:42

标签: java android generics

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;

在上面的例子中,iInstance变量工作正常。但是,iInstance变量在添加泛型部分时显示错误

  

在原始类型

上输入类型参数

如果我从变量中删除了泛型部分,那么下面的测试用例将失败并出现类型错误

public class ExtendedOuter extends OuterClass<ExtendedOuter> {

}

// This only works on OuterClass<?> and not on OuterClass
ExtendedOuter eInstance = oInstance.parse(ExtendedOuter.class);
  

找到:OuterClass,必需:ExtendedOuter

静态/外部类没有问题,因为它们可以定义为ClassName<?>,但不能使用<?>定义非静态内部类

如何在不<?>静态的情况下将iInstance添加到InnerClass

修改 让我举几个例子说明为什么这些类使用它们的扩展版本作为泛型。

public abstract class OuterClass<OT extends OuterClass<OT>> {
    public abstract OT returnMe();
}

public class ExtendedOuter extends OuterClass<ExtendedOuter> {
    @Override
    public ExtendedOuter returnMe() {
        return this;
    }
}

如果我只是在抽象版本上创建了返回类型OuterClass,则上面的示例将不起作用。如果是这样的话,任何扩展版本都必须在使用这种方法时进行铸造,这种方法并不理想。

<CT>

中删除<T extends OuterClass<CT>>后,AndroidStudio也出现了错误
  

参数OT不在其范围内

执行ClassName extends OuterClass<ClassName>时,此错误会显示在扩展类中。换句话说,它只能在抽象类上使用<T extends OuterClass>

2 个答案:

答案 0 :(得分:0)

类似于之前的post我展示了一个构建器模式,它使用泛型类型和继承来减少继承情况下的实际代码,这对于非静态类也是可能的。因此,我相应地修改了构建器示例以避免静态内部类:

带有父级构建器的父类:

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() +"]";
    }
}

具有非静态构建器的子类看起来像这样:

@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;
    }
}

要测试此外部/内部类的功能,您可以实现以下内容:

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());
    }
}

TestParamBTestParamA相同 - 它仅包含FG的varialbe和builder-methods,而不是DE 。此外,DEFG只是具有简单toString()实现的类,只返回简单的类名。

这将打印以下输出:

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]

答案 1 :(得分:0)

  

但是,添加泛型时iInstance变量显示错误   部分

     

在原始类型

上输入类型参数

首先,这不是你应该得到的问题,因为范围内没有定义InnerClass。作为一个内部类,它的范围在外部类的范围内。因此,当它在外部类之外时,您需要使用外部类明确限定它,否则它将为您提供InnerClass符号未找到错误。所以你没有显示你的真实代码(也许你在某处有另一个InnerClass)或者没有显示你真正的错误。

  

如果我从变量中删除泛型部分,那么下面的测试   案例将因类型错误而失败

当您使用原始类型访问成员时,会关闭这些成员上的所有泛型。因此.parse()被删除为public OuterClass parse(Class clazz)(即使方法未使用CT也是如此),这就是为什么oInstance.parse(ExtendedOuter.class)返回类型OuterClass的原因与ExtendedOuter不兼容。

  

如何在不使InnerClass静态的情况下将<?>添加到iInstance?

OuterClass<?>.InnerClass<?>OuterClass<Something>.InnerClass<SomethingElse>