类继承和泛型类型

huangapple go评论72阅读模式
英文:

Class inheritance and generic types

问题

我目前正在研究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);
        }
}
英文:

I'm currently working on inheritance in Java. I would like to discuss the following case with you.

In my example, I have numerous animal and enclosure classes. All animals are derived from BaseAnimal. All enclosure are derived from BaseEnclosure. Both base classes provide various concrete methods - but also some abstract methods.

Now, when implementing a CatEnclosure, I want to specify that when CatEnclosure.resettleTo(Enclosure) is called, only one cat enclosure can be passed. In my current code, a cat could also be placed with a dog.

To my understanding, I would have to define the class of the future (derived) class when creating the abstract method resettleTo in the BaseEnclosure class.

My idea was to use a second generic. So BaseEnclosure&lt;A&gt; becomes BaseEnclosure&lt;E, A&gt;. But now I would also have to specify that E must be derived from BaseEnclosure. In addition, of course, A should also be of the BaseAnimal type.

So I get: BaseEnclosure&lt;E extends BaseEnclosure, A extends BaseAnimal&gt;

My IDE now complains that BaseEnclosure and BaseAnimal are raw types. If I write BaseEnclosure&lt;E extends BaseEnclosure&lt;?,?&gt;, A extends BaseAnimal&lt;?,?&gt;&gt;, it works. However, I don't know whether all of this makes sense in terms of design.

I look forward to your suggestions.

Enclosed you get the example code.

public abstract class BaseAnimal&lt;E&gt; {
        protected E enclosure;
       
        public void setEnclosure(E enclosure) {
                this.enclosure = enclosure;
        }
       
        public E getEnclosure() {
                return enclosure;
        }
       
        public abstract String getNoise();
}
public abstract class BaseEnclosure&lt;A&gt; {
        protected List&lt;A&gt; animals = new ArrayList&lt;A&gt;();
       
        // some methods...
       
        public List&lt;A&gt; getAnimals() {
                return animals;
        }
       
        public abstract void resettleTo(BaseEnclosure other);
}
public class Cat extends BaseAnimal&lt;CatEnclosure&gt; {
 
        @Override
        public String getNoise() {
                return &quot;miiiaaauu&quot;;
        }
}
public class CatEnclosure extends BaseEnclosure&lt;Cat&gt;{
 
        @Override
        public void resettleTo(BaseEnclosure other) {
                // hm...
        }
}
public class Dog extends BaseAnimal&lt;DogEnclosure&gt; {
 
        @Override
        public String getNoise() {
                return &quot;wuff&quot;;
        }
}
public class DogEnclosure extends BaseEnclosure&lt;Dog&gt;{
 
        // 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);
        }
}

答案1

得分: 1

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

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

您的情况是泛型中循环引用的典型案例。根据这个帖子,您需要重新定义基类如下:

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> {...}
// 类似地,Cat和CatEnclosure

现在,为了防止猫围栏重新安置到狗围栏,您需要更改resettleTo方法的签名如下:
public abstract void resettleTo(BaseEnclosure<E, A> 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); // 错误,类型不匹配
英文:

> I want to specify that when CatEnclosure.resettleTo(Enclosure) is called, only one Cat Enclosure can be passed. In my current code, a cat could also be placed with a dog.

Assuming here, you dont want CatEnclosure to resettleTo DogEnclosure.

Your scenario is a typical case of circular reference in generics. Based on this post, you need to redefine your base classes as follows:

public abstract class BaseAnimal&lt;A extends BaseAnimal&lt;A, E&gt;, E extends BaseEnclosure&lt;E, A&gt;&gt; {...}

public abstract class BaseEnclosure&lt;E extends BaseEnclosure&lt;E, A&gt;, A extends BaseAnimal&lt;A, E&gt;&gt; {...}

class Dog extends BaseAnimal&lt;Dog, DogEnclosure&gt; {...}
class DogEnclosure extends BaseEnclosure&lt;DogEnclosure, Dog&gt; {...}
// Similarly Cat and CatEnclosure

Now, to prevent cat enclosure resettling to dog enclosure, you need to change the resettleTo method signature as below:
public abstract void resettleTo(BaseEnclosure&lt;E,A&gt; other);

You will not be allowed to compile the below code:

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

huangapple
  • 本文由 发表于 2020年10月21日 04:00:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/64452523.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定