代码之家  ›  专栏  ›  技术社区  ›  Kris Nuttycombe

Java字段类型,用于一般递归自类型的值?

  •  4
  • Kris Nuttycombe  · 技术社区  · 17 年前

    给定一个类层次结构,其中基类定义递归的自身类型:

    abstract class A<T extends A<T>> { }
    

    如何声明另一个类(在T中不应该是泛型的,因为这样的T可能在对象的生命周期中发生变化),该类的字段可以包含a的任何子类?

    以下内容不起作用:

    public class B {
        //fails to compile, because the capture of ? is not sufficiently narrow
        private A<?> a;
    
        public <T extends A<T>> setA(T a) {
            this.a = a;
        }
    }
    

    --问题结束--

    我注意到一些stackoverflow成员倾向于用“为什么首先要这样做?”以下是我使用此模式的一个理由——您可以注意到,Java标准库在EnUM类的定义中也使用递归自类型: Enum<E extends Enum<E>> . 这个问题也可以类似地被问到“如何定义类型的字段” Enum<?> .

    对正示例:

    abstract class A<T extends A<T>> {
        public abtract T self();
        public B<T> bify(Bifyer bifyer) {
            return bifyer.bify(self());
        }
    }
    

    子类:

    class ASub1 extends A<ASub1> { 
        public ASub1 self() { return this; }
    }       
    
    class ASub2 extends A<ASub2> { 
        public ASub2 self() { return this; }
    }       
    

    绑定到并行类层次结构:

    abstract class B<T extends A<T>> {
    }
    
    class BSub1<T extends A<T>> implements B<T> { }
    class BSub2<T extends A<T>> implements B<T> { }
    //and others
    

    通过实现双层接口管理B实例的生成:

    interface Bifyer {
        B<ASub1> bify(ASub1 asub1);
        B<ASub2> bify(ASub2 asub2);        
    }
    

    此接口的实现可能返回b的bsub1或bsub2。这本质上是一个访问者模式的应用程序,其中biffer是访问者,但与标准访问者不同,accept方法返回的是一个值而不是void。这提供了一个模块化框架,其中可以指定不同的双层实现来为bify方法提供可选的行为和返回类型,比如为b的每个子类指定一个。

    1 回复  |  直到 12 年前
        1
  •  4
  •   Luke Woodward    17 年前

    如果绑定通配符 ? 下面由 A ,它应该工作:

    public class B {
        private A<? extends A> a;
    
        public <T extends A<T>> void setA(T a) {
            this.a = a;
        }
    }