Java 使用泛型避免instanceof

Java 使用泛型避免instanceof,java,generics,Java,Generics,我需要添加到子属性(ProductOption和ProductAttribute)列表中,这些子属性是名为Product的父对象的属性。这三个类都扩展了一个抽象类CMS 我想一般性地调用方法“attachChildToParent”,但我延迟了的实例并将其转换为产品,从而延迟了不可避免的过程 有没有一种方法可以让我写这篇文章,这样我就可以避免演员阵容 要测试: package puzzler; import java.util.ArrayList; import java.util.List;

我需要添加到子属性(ProductOption和ProductAttribute)列表中,这些子属性是名为Product的父对象的属性。这三个类都扩展了一个抽象类CMS

我想一般性地调用方法“attachChildToParent”,但我延迟了
的实例并将其转换为产品,从而延迟了不可避免的过程

有没有一种方法可以让我写这篇文章,这样我就可以避免演员阵容

要测试:

package puzzler;

import java.util.ArrayList;
import java.util.List;

public class Tester {
    public static void main(String[] args) {
        Product p = new Product();
        ProductAttribute pa = new ProductAttribute();
        ProductOffering po = new ProductOffering();

        List<ProductAttribute> lpa = new ArrayList<ProductAttribute>();
        List<ProductOffering> lpo = new ArrayList<ProductOffering>();

        attachChildToParent(lpa, p);
    }

    static void attachChildToParent(List<? extends CMS> listChild, Product parent) {
        for (CMS cmsItem : listChild) {
            parent.attach(cmsItem);         
        }
    }
}
二级儿童

package puzzler;

import puzzler.CMS;

public class ProductOffering extends CMS {
    String node;

    public String getNode() {
        return node;
    }

    public void setNode(String node) {
        this.node = node;
    }
}

您可以通过使用访问者模式来解决铸造问题:在
CMS
类中,添加一个新的(抽象)方法
attachTo(产品父级)
。在每个子类中,您都可以实现此方法来调用父类上的attach,正确的函数将得到解决。

您可以使用visitor模式解决铸造问题:在您的
CMS
类中,添加一个新的(抽象)方法
attachTo(产品父类)
。在每个子类中,您都可以实现此方法来调用父类上的attach,并将解析正确的函数。

覆盖

public void attach(ProductOffering cms) {
   this.getLpo().add(cms);
}

public void attach(ProductAttribute cms) {
   this.getLpa().add(cms);
}
覆盖

public void attach(ProductOffering cms) {
   this.getLpo().add(cms);
}

public void attach(ProductAttribute cms) {
   this.getLpa().add(cms);
}

委派给子类:

public void attach(CMS cms) {
    cms.callAdd(this);

}
在CMS上添加:

public abstract void callAdd(Product product);
在ProductOffering上添加:

public void callAdd(Product product) {
   getLpo().add(this)       
}

ProductAttribute…

的类似委托给子类:

public void attach(CMS cms) {
    cms.callAdd(this);

}
在CMS上添加:

public abstract void callAdd(Product product);
在ProductOffering上添加:

public void callAdd(Product product) {
   getLpo().add(this)       
}

ProductAttribute的一个类似例子…

有一些方法可以避免这种情况,但泛型不能。泛型允许您编写允许避免强制转换的代码,但当您需要避免
instanceof
时,它没有帮助。主要原因是,所有具有泛型类型的变量在内部都被视为
Object

这就是为什么当您从
attachChildToParent()
调用它时,编译器使用泛型
attach(CMS)
方法:要附加的子对象的类型将是
CMS
——编译器无法保留您在调用
attachChildToParent()时使用的类型

唯一的解决方案是在子对象中编写附加方法:

public class ProductAttribute extends CMS {
    @Override
    public void attachTo( Product p ) {
        p.getLpo().add( this );
    }
}

有一些方法可以避免这种情况,但泛型不能。泛型允许您编写允许避免强制转换的代码,但当您需要避免
instanceof
时,它没有帮助。主要原因是,所有具有泛型类型的变量在内部都被视为
Object

这就是为什么当您从
attachChildToParent()
调用它时,编译器使用泛型
attach(CMS)
方法:要附加的子对象的类型将是
CMS
——编译器无法保留您在调用
attachChildToParent()时使用的类型

唯一的解决方案是在子对象中编写附加方法:

public class ProductAttribute extends CMS {
    @Override
    public void attachTo( Product p ) {
        p.getLpo().add( this );
    }
}

仿制药不能解决你的问题。由于在
之后丢失了特定于实例的信息,泛型无法解决您的问题。由于您在
之后丢失了特定于实例的信息,我已经很久没有使用java了,但在C#中,您可以这样声明:FatherType foo=new ChildType();ListI已经很久没有使用java了,但在C#中,可以这样做声明:FatherType foo=new ChildType();这个代码已经存在了:问题是调用站点只知道这个超类,它在run-time.Doh中并没有消除歧义!对不起,我刚才仔细看了一下,你是对的。我不认为泛型会有帮助,因为运行时类型擦除。我会想一想,但是因为您有一个逻辑分支,所以在将实际实现传递到方法时,需要在运行时区分它。您可能需要进一步重新思考这个问题。这段代码已经存在:问题是调用站点只知道超类,在运行时它不会消除歧义。Doh!对不起,我刚才仔细看了一下,你是对的。我不认为泛型会有帮助,因为运行时类型擦除。我会想一想,但是因为您有一个逻辑分支,所以在将实际实现传递到方法时,需要在运行时区分它。你可能需要进一步思考这个问题。谢谢。这是我最初的方法,但它假设父对象始终是产品。事实上,这种情况可能永远都会发生,我想得太多了。但是这个难题确实困扰着我。您也可以创建一个接口,并在
attachTo()
中将其用作参数类型。这将允许您说“这个孩子可以附加到任何具有方法
getLpo()
”的东西上。”谢谢。这是我最初的方法,但它假设父对象始终是产品。事实上,这种情况可能永远都会发生,我想得太多了。但是这个难题确实困扰着我。您也可以创建一个接口,并在
attachTo()
中将其用作参数类型。这将允许您说“这个子对象可以附加到任何具有方法
getLpo()
的对象。”