英文:
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现在抱怨BaseEnclosure
和BaseAnimal
是原始类型。如果我写上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<A>
becomes BaseEnclosure<E, A>
. 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<E extends BaseEnclosure, A extends BaseAnimal>
My IDE now complains that BaseEnclosure
and BaseAnimal
are raw types. If I write BaseEnclosure<E extends BaseEnclosure<?,?>, A extends BaseAnimal<?,?>>
, 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<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);
}
}
答案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<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
Now, to prevent cat enclosure resettling to dog enclosure, you need to change the resettleTo method signature as below:
public abstract void resettleTo(BaseEnclosure<E,A> 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论