【问题标题】:Generic use of a class nested in a generic嵌套在泛型中的类的泛型使用
【发布时间】:2016-12-13 14:27:41
【问题描述】:

即使这不是一个好习惯,我也想知道为什么要知道。

下面的代码无法编译,我真的不明白为什么。


假设我对小丑、女王和国王有一个抽象的定义:

abstract class JokerA {
    //JokerA does things
}

abstract class QueenA<J extends JokerA> {
    //QueenA makes use of J
    class Princess {
        void receiveGift(Gift gift) {
            /* ... */
        }
    }
}

abstract class KingA<Q extends QueenA<?>> {
    KingA(Q.Princess princess) {
        Gift giftForPrincess = new Gift();
        princess.receiveGift(giftForPrincess);
    }
}

这很好用。 但是,我也想定义一个更专业但仍然抽象的小丑、女王和国王

abstract class JokerB extends JokerA {
    //JokerB does some things differently
}

abstract class QueenB<J extends JokerB> extends QueenA<J> {
    //QueenB makes use of J sometimes differently, because she knows how JokerBs behave
}

abstract class KingB<Q extends QueenB<?>> extends KingA<Q> {
    KingB(Q.Princess princess) {
        super(princess); //error
    }
}

错误是:

KingA(QueenA<capture<?>>.Princess) in KingA cannot be applied to (Q.Princess)

但是,我看不出公主级会有什么不同。

谁能赐教?

【问题讨论】:

    标签: java generics inner-classes


    【解决方案1】:

    首先,这里只有一个类名为Princess,即QueenA.Princess。没有QueenB.Princess——如果你写QueenB.Princess,编译器只会把它理解为QueenA.Princess。注意,由于PrincessQueenA的非静态内部类,泛型类,QueenA.Princess也是泛型类(通过QueenA的参数进行参数化)。当它被参数化时,它看起来像QueenA&lt;something&gt;.Princess

    由于问题是Princess 类的两个值之间的兼容性问题,并且我们在上面提到有一个这样的类,唯一的兼容性问题是关于泛型类型参数。传入super() 的类型应该是Q.Princess。但正如我们上面提到的,Princess 属于QueenA,而不是QueenBQ。因此编译器在编译时会自动将其重写为QueenA&lt;something&gt;.Princess。问题是something 是什么。基本上,问题是QQueenA&lt;what&gt;Q 是绑定QueenB&lt;?&gt; 的类型变量。这意味着有人可以使用这个类,QQueenB&lt;X&gt;X 是任何满足 QueenB 的类型参数边界的类型(即扩展 JokerB 的类型)。所以我们不能假设任何关于X 的东西,除非它是JokerB 的一个子类型。 QueenB&lt;X&gt; 扩展了QueenA&lt;X&gt;,所以这意味着QQueenA&lt;X&gt;&lt;capture ...&gt; 只是编译器打印来表示未知类型的东西。所以此时,编译器已经发现Q.Princess 真正的意思是QueenA&lt;some unknown type that extends JokerB&gt;.Princess

    然后你将它传递给super()KingA 的构造函数。这个类型参数的参数类型也写成Q.Princess(注意:这是KingAQ,不同的类型参数;不要搞混了)。如果你按照上面同样的分析,你会看到编译器看到这个Q.Princess真的意味着QueenA&lt;some unknown type that extends JokerA&gt;.Princess

    问题是,QueenA&lt;first unknown subtype&gt;.PrincessQueenA&lt;second unknown subtype&gt;.Princess 的子类型吗?即first unknown subtype 是否与second unknown subtype 相同? (记住泛型是不变的。)编译器只看这个就会说它不知道它们是否相同,因为两个未知类型肯定可能不同,所以它们不兼容。

    你可能会说,等一下,你知道Q 是某个未知类型XQueenA&lt;X&gt;KingB&lt;Q&gt; 被声明为扩展KingA&lt;Q&gt;,所以QKingB特定对象的作用域与KingB 作用域中的Q 相同。所以Qs 是一样的,未知的X 在这两种情况下都是一样的。但这不适用于这里,因为 Q 不再被考虑。请记住,没有类型 Q.Princess。它表示的真实类型是QueenA&lt;something&gt;.PrincessQueenA&lt;something&gt;.Princess 是在编译每个类的每个构造函数时在编译时计算出来的。一旦确定为unknown type,则将其固定为unknown type,并且与类的类型参数Q 无关。所以这两种未知类型没有关系。

    您可以通过使用新的类型参数而不是让编译器推断未知类型来解决它。然后,类型参数可以允许您连接类型的不同用途,让编译器知道它们是相同的类型。像这样的:

    abstract class KingA<J extends JokerA, Q extends QueenA<J>> {
        KingA(Q.Princess princess) {
            Gift giftForPrincess = new Gift();
            princess.receiveGift(giftForPrincess);
        }
    }
    
    abstract class KingB<J extends JokerB, Q extends QueenB<J>> extends KingA<J, Q> {
        KingB(Q.Princess princess) {
            super(princess);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-03
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 2023-01-10
      相关资源
      最近更新 更多