【问题标题】:Class inheritance and generic types类继承和泛型类型
【发布时间】:2020-10-20 20:00:51
【问题描述】:

我目前正在研究 Java 中的继承。我想和你讨论以下案例。

在我的示例中,我有许多动物和围栏类。所有动物均来自BaseAnimal。所有外壳均源自BaseEnclosure。两个基类都提供了各种具体的方法——但也提供了一些抽象方法。

现在,在实现CatEnclosure时,我想指定当CatEnclosure.resettleTo(Enclosure)被调用时,只能通过一个猫圈。在我当前的代码中,猫也可以和狗放在一起。

据我了解,在 BaseEnclosure 类中创建抽象方法 resettleTo 时,我必须定义未来(派生)类的类。

我的想法是使用第二个泛型。所以BaseEnclosure<A> 变成了BaseEnclosure<E, A>。但现在我还必须指定E 必须派生自BaseEnclosure。此外,当然A 也应该是BaseAnimal 类型。

所以我得到:BaseEnclosure<E extends BaseEnclosure, A extends BaseAnimal>

我的 IDE 现在抱怨 BaseEnclosureBaseAnimal 是原始类型。如果我写BaseEnclosure<E extends BaseEnclosure<?,?>, A extends BaseAnimal<?,?>>,它可以工作。但是,我不知道所有这些在设计方面是否有意义。

期待您的建议。

附上示例代码。

public abstract class BaseAnimal<E> {
        protected E enclosure;
       
        public void setEnclosure(E enclosure) {
                this.enclosure = enclosure;
        }
       
        public E getEnclosure() {
                return enclosure;
        }
       
        public abstract String getNoise();
}
public abstract class BaseEnclosure<A> {
        protected List<A> animals = new ArrayList<A>();
       
        // some methods...
       
        public List<A> getAnimals() {
                return animals;
        }
       
        public abstract void resettleTo(BaseEnclosure other);
}
public class Cat extends BaseAnimal<CatEnclosure> {
 
        @Override
        public String getNoise() {
                return "miiiaaauu";
        }
}
public class CatEnclosure extends BaseEnclosure<Cat>{
 
        @Override
        public void resettleTo(BaseEnclosure other) {
                // hm...
        }
}
public class Dog extends BaseAnimal<DogEnclosure> {
 
        @Override
        public String getNoise() {
                return "wuff";
        }
}
public class DogEnclosure extends BaseEnclosure<Dog>{
 
        // some methods...
       
        @Override
        public void resettleTo(BaseEnclosure other) {
                // hm...
        }
}
public class Main {
       
        public static void main(String[] args) {
                DogEnclosure doghouse = new DogEnclosure();
                Dog dog = new Dog();
                // later: JPA
                doghouse.getAnimals().add(dog);
                dog.setEnclosure(doghouse);
               
                CatEnclosure catbox = new CatEnclosure();
                Cat cat = new Cat();
                // later: JPA
                catbox.getAnimals().add(cat);
                cat.setEnclosure(catbox);
               
                // OHOHOH!!!
                doghouse.resettleTo(catbox);
        }
}

【问题讨论】:

标签: java generics inheritance design-patterns


【解决方案1】:

我想指定当调用CatEnclosure.resettleTo(Enclosure)时,只能传递一个Cat Enclosure。在我当前的代码中,猫也可以和狗放在一起。

假设在这里,您不希望 CatEnclosure 重新安置到 DogEnclosure。

您的场景是泛型中循环引用的典型案例。基于这个post,你需要重新定义你的基类如下:

public abstract class BaseAnimal<A extends BaseAnimal<A, E>, E extends BaseEnclosure<E, A>> {...}

public abstract class BaseEnclosure<E extends BaseEnclosure<E, A>, A extends BaseAnimal<A, E>> {...}

class Dog extends BaseAnimal<Dog, DogEnclosure> {...}
class DogEnclosure extends BaseEnclosure<DogEnclosure, Dog> {...}
// Similarly Cat and CatEnclosure

现在,为了防止猫笼重新安置到狗笼,您需要将resettleTo方法签名更改为如下:
public abstract void resettleTo(BaseEnclosure&lt;E,A&gt; other);

您将不能编译以下代码:

CatEnclosure catEnclosure = new CatEnclosure();
Cat c = new Cat();
c.setEnclosure(catEnclosure);

DogEnclosure dogEnclosure = new DogEnclosure();
Dog d = new Dog();
d.setEnclosure(dogEnclosure);

catEnclosure.resettleTo(dogEnclosure); // Error type mismatch

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 2015-09-15
    • 1970-01-01
    • 2021-10-11
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多