Java 用泛型实现父子关系

Java 用泛型实现父子关系,java,generics,Java,Generics,我正在尝试创建一个容器(父对象),您可以在其中指定它可以包含的对象(子对象)的类型 类似地,您可以指定子级的父级类型。 父对象和子对象将来需要通信,因此我需要它们都具有彼此的对象引用 此代码是我的应用程序中实际代码的更简单表示形式 class Parent<T extends Child> { ArrayList<T> childObjects; public void addChildChild(T newChild) { childOb

我正在尝试创建一个容器(父对象),您可以在其中指定它可以包含的对象(子对象)的类型

类似地,您可以指定子级的父级类型。 父对象和子对象将来需要通信,因此我需要它们都具有彼此的对象引用

此代码是我的应用程序中实际代码的更简单表示形式

class Parent<T extends Child> {
    ArrayList<T> childObjects;
    public void addChildChild(T newChild) {
        childObjects.add(newChild);
        newChild.setParent(this);
    }
    public void newChildConnected(T connectedChild) {
        System.out.println("Child connected");
    }
}

class Child <T extends Parent> {
    T parentObject;
    public void setParent(T newParent) {
        parentObject = newParent;
        parentObject.newChildConnected(this);
    }
}
类父类{
ArrayList子对象;
公共无效addChildChild(T newChild){
添加(newChild);
newChild.setParent(this);
}
public void newChildConnected(T connectedChild){
System.out.println(“子连接”);
}
}
班童{
T父对象;
公共void setParent(T newParent){
parentObject=newParent;
parentObject.newChildConnected(此);
}
}
我的IDE说: 作为原始类型“test.Parent”的成员对“newChildConnected(T)”的未选中调用

我一直在尝试不同的方法,以使它更好地与通配符和东西,但我认为这是我能做的最好的。 那么,实施这种行为的正确方式是什么呢

我的目标是能够指定父对象的子类型和子对象的父类型,并以这样的方式执行,即子对象和父对象都能够在不使用intanceof()运算符和强制转换的情况下使用彼此的功能。(这就是我使用泛型的原因)


甚至在Java中也是可能的?

泛型类型的使用会创建一个循环类型引用。如果父类和子类的类型(或接口/基类)相同,请在单个类中使用树结构:

class MyObject<T> {
T parentObject;
ArrayList<T> childObjects = new ArrayList();
public void addChildChild(T newChild) {
    childObjects.add(newChild);
    newChild.setParent(this);
}
public void newChildConnected(T connectedChild) {
    System.out.println("Child connected");
}
public void setParent(T newParent) {
    parentObject = newParent;
    parentObject.newChildConnected(this);
}
类MyObject{
T父对象;
ArrayList childObjects=新建ArrayList();
公共无效addChildChild(T newChild){
添加(newChild);
newChild.setParent(this);
}
public void newChildConnected(T connectedChild){
System.out.println(“子连接”);
}
公共void setParent(T newParent){
parentObject=newParent;
parentObject.newChildConnected(此);
}
使用此类时,必须检查
parentObject==null
的顶级对象和
childObjects.size()==0
的叶对象


如果没有公共接口或基类,这是不可能安全完成的。

正如@Strom正确指出的那样,没有基类或接口,就无法以类型安全的方式完成

如果可以扩展类/接口,则不带任何强制转换的类型安全解决方案将如下所示:

interface BaseParent<P extends BaseParent<P, C>, C extends BaseChild<P, C>> {

    List<C> getChildren();

    void setChildren(List<C> children);

    P self();

    default void addChild(C child) {
        if (child.getParent() == null) {
            child.setParent(self());
        }

        final ArrayList<C> newChildren = new ArrayList<>(getChildren());
        newChildren.add(child);
        setChildren(newChildren);
    }
}

interface BaseChild<P extends BaseParent<P, C>, C extends BaseChild<P, C>> {

    void setParent(P parent);

    P getParent();

}

final class Parent implements BaseParent<Parent, Child> {

    private List<Child> children = new ArrayList<>();

    @Override
    public List<Child> getChildren() {
        return children;
    }

    @Override
    public void setChildren(List<Child> children) {
        this.children = children;
    }

    @Override
    public Parent self() {
        return this;
    }
}

final class Child implements BaseChild<Parent, Child> {

    private Parent parent;

    public Child(Parent parent) {
        this.parent = parent;
        this.parent.addChild(this);
    }

    @Override
    public void setParent(Parent parent) {
        this.parent = parent;
    }

    @Override
    public Parent getParent() {
        return parent;
    }
}
接口BaseParent{
列出getChildren();
无效设置子项(列出子项);
P self();
默认的void addChild(C child){
if(child.getParent()==null){
setParent(self());
}
final ArrayList newChildren=新ArrayList(getChildren());
newChildren.add(child);
setChildren(newChildren);
}
}
接口BaseChild{
void setParent(P parent);
P getParent();
}
最后一个类Parent实现BaseParent{
private List children=new ArrayList();
@凌驾
公共列表getChildren(){
返回儿童;
}
@凌驾
公共子项(列出子项){
这个。孩子=孩子;
}
@凌驾
公共父母自我(){
归还这个;
}
}
最后一个类Child实现BaseChild{
私人家长;
公共子(父/母){
this.parent=parent;
this.parent.addChild(this);
}
@凌驾
公共void setParent(父级){
this.parent=parent;
}
@凌驾
公共父getParent(){
返回父母;
}
}

该解决方案使用类型安全和a来避免强制转换。这两种方法都有警告,并且不是完全安全的,因为您必须依赖基/类接口的实现者来返回正确的自类型并定义正确的类型参数,但对于内部API来说应该足够好。

我认为这是不可能的,不是。See“类型安全异质容器”在Joshua Bloch的有效Java for a better方法中。我的第一种方法忽略原始类型警告是否有任何危险?当然,它不是类型安全的。您可以/应该防止原始类型,例如,通过编写
T extends Child
T extends Parent>
,将警告转化为错误,指示类型,在这一点上,是完全不兼容的。可能有一些解决方法,但考虑到伪代码,很难说什么是最合适的…@JerryLundegaard它将允许类似
new ChildA().setParent(new ParentB())
使用
类ParentB扩展了Parent
。因此,最终的结果是家长只希望childB拥有ChildA。