我有一个继承问题,用代码而不是文本更容易解释问题,因此给出 Parent
的以下继承设计s:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Parent<T extends Offspring> {
@OneToMany(mappedBy = "parent", targetEntity = Offspring.class)
private Set<T> offsprings;
// Getters/Setters relevant for all sub types
}
@Entity
public class Cat extends Parent<Kitten> {
}
@Entity
public class Dog extends Parent<Puppy> {
}
还有Offspring
:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Offspring<T extends Parent> {
@ManyToOne(targetEntity = Parent.class)
@JoinColumn(name = "parent_id", referencedColumnName = "id")
private T parent;
// Getters/Setters relevant for all sub types
}
@Entity
public class Kitten extends Offspring<Cat> {
}
@Entity
public class Puppy extends Offspring<Dog> {
}
假设我想获取 parent 名单:List<Parent> parents = parentService.getAll();
父列表,因为它现在是原始类型,所以不理解 parents..get(0).getOffsprings()
应该返回类型 Set<Offspring>
。相反,由于原始类型,它认为它返回 Set
.
我可能想这样做,因为 Person
可能有一个包含所有Parent
的列表就像:
@Entity
public class Person {
@OneToMany(mappedBy = 'person')
private Set<Parent> parents;
}
我可能想要获得该人拥有的所有 parent 的所有后代:person.getParents().get(0).getOffsprings()
但这会返回类型 Set
因为它是原始类型。
显然我走错了路,所以:
目标是:
- 能够拥有
Cat
的对象并且只能放Kitten
后代进入其集合。或者Puppy
的对象并且只能是 可以设置Dog
作为其父级。 - 能够查询所有
Parent
s 并让它保持打字状态 那只是Offspring
可以放入对象中。
对于如何完成此操作,我经历了许多不同的排列。例如,一种选择是 Cat
对象来容纳其自己的容器 Kitten
后代:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Parent {
@OneToMany(mappedBy = "parent")
private Set<Offspring> offsprings;
}
@Entity
public class Cat extends Parent {
private Set<Cat> offsprings;
}
但这不起作用,因为 Cat
类无法覆盖父类的 getter/setter Parent
。以及导致 Hibernate 问题,因为它现在数据库表 Kitten
有一个链接到Cat
.
免责声明
我可能会遗漏一些明显的东西,或者以完全错误的方式处理这个问题,所以我愿意接受关于处理这个问题的最佳方法的建议。此外,我的继承策略可能会导致问题,因此欢迎所有建议,如果需要,我很乐意提供更多建议。
最佳答案
看起来您正在寻找的是 abstract
类(和方法)。这些允许您指定行为并将实现留给其子类。我会做Parent
和Offspring
abstract class
es,然后继承它们,同时指定确切的返回类型:
public abstract class Parent {
public abstract Set<? extends Offspring> getOffsprings();
}
public abstract class Offspring {
public abstract Parent getParent();
}
public class Cat extends Parent {
private Set<Kitten> offsprings;
@Override
public Set<Kitten> getOffsprings() {
return offsprings;
}
}
public class Kitten extends Offspring {
private Cat parent;
@Override
public Cat getParent() {
return parent;
}
}
public class Dog extends Parent {
private Set<Puppy> offsprings;
@Override
public Set<Puppy> getOffsprings() {
return offsprings;
}
}
public class Puppy extends Offspring {
private Dog parent;
@Override
public Dog getParent() {
return parent;
}
}
而Offspring
类规定了一个返回 Parent
的方法,它的子类可以返回它的子类型,如 Cat
或Dog
。我相信它的名字叫Liskov substitution principle .
说到Animal
,它规定了一个返回 Set<? extends Offspring>
的方法,这意味着“扩展 Offspring
的特定单一类型”(与 Set<Offspring>
相反,这意味着“任何 Offspring
”,并且会给您一个编译错误)。这允许子类型返回 Set
他们的特定Offspring
,例如 Set<Kitten>
或Set<Puppy>
.
现在,当你有 List<Parent> parents = parentService.getAll();
每个Parent
将返回 Set<? extends Offspring>
通过parent.getOffsprings()
.
关于java - 存在原始打字问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51963500/