更正用于将对象添加到方法中的列表的泛型类型

时间:2018-03-25 14:02:43

标签: java generics

我有一系列形状(SVGShape)并希望使用单个方法将它们添加到列表中(这将执行更多逻辑)。添加SVGCircle的代码有效但重复。 SVGEllipse的代码表示我想要做的事情,因此有一个方法不知道它传递了哪种类型,但无法编译。一般类型是(我认为)List<? extends SVGShape>但这禁止添加元素(在编译时)。 我正在尝试做什么或是否需要重写?

// SVGCircle extends SVGShape
// SVGEllipse extends SVGShape
// List<SVGEllipse> ellipseList;
// List<SVGCircle> circleList;
for (SVGShape shape : shapeList) {
    if (shape instanceof SVGCircle) {
        SVGCircle circle = (SVGCircle) shape; // this compiles and works
        circleList.add(circle);
        circle.setId("circle"+circleList.size());
    } else if (shape instanceof SVGEllipse) {
        SVGEllipse ellipse = (SVGEllipse) shape;
        addToListAndSetId(ellipseList, ellipse); // fails to compile
    }
}
private void addToListAndSetId(List<SVGShape> shapeList, SVGShape shape) {
    shapeList.add(shape);
    // more logic here
    shape.setId(shape.getLocalName().toLowerCase() + shapeList.size());
}

注意:2个答案现在已经给出了正确的方法形式。为了完整起见,修改后的调用语法为:

if (shape instanceof SVGCircle) {
    addToListAndSetId(circleList, (SVGCircle) shape);
} else if (shape instanceof SVGEllipse) {
    addToListAndSetId(ellipseList, (SVGEllipse) shape);
}

3 个答案:

答案 0 :(得分:4)

如果您将方法的签名更改为void addToListAndSetId(List<? extends SVGShape>, SVGShape shape),则它不允许添加List,因为没有任何内容阻止您转到方法List<SVGEllipse>使用SVGRectangle(您不应该将其添加到List)。

您可以在方法中添加泛型类型参数:

private <T extends SVGShape> void addToListAndSetId(List<T> shapeList, T shape) {
    shapeList.add(shape);
    // more logic here
    shape.setId(shape.getLocalName().toLowerCase() + shapeList.size());
}

这样,如果第一个参数是List<SVGEllipse>,则第二个参数必须是SVGEllipse,可以安全地添加到该列表中。

答案 1 :(得分:2)

您可能想要使用泛型。

private <T extends SVGShape> void addToListAndSetId(List<T> shapeList, T shape) {
    shapeList.add(shape); // more logic here    
    shape.setId(shape.getLocalName().toLowerCase() + shapeList.size());
 }

答案 2 :(得分:0)

编辑:在函数中强制类型匹配的更好方法是使用Eran在他的答案中提到的T extends SVGShape,因此函数<T extends SVGShape> void addToListAndSetId2(List<T> list, T shape)是更好的解决方案,因为不匹配的参数不会编译(根据需要):

//List<SVGEclipse> eclipses;
//SVGCircle circle;

addToListAndSetId2(eclipses, circle); // this will not compile as required


//List<SVGShape> eclipses;
//SVGCircle circle;

addToListAndSetId(eclipses, circle); // this will compile although should NOT

----编辑前:

您应该创建泛型类型的列表而不是 List<SVGCircle>, List<SVGEclipse>使用类似List<SVGShape> or List<ISVGShape>的通用类或接口。

以下是在编译时工作的代码段。我还根据您的问题详细信息列出了我假设的其他课程:

public static void main(String []args) {

        List<SVGShape> shapes = new ArrayList<>();
        // cirlce list of generic type
        List<SVGShape> circleList = new ArrayList<>();
        // eclipse list fof generic type
        List<SVGShape> ecliplseList = new ArrayList<>();

        for(SVGShape shape: shapes) {
            if(shape instanceof SVGCircle) {
                SVGCircle svgCircle = (SVGCircle) shape;
                svgCircle.setId("some-id");
                circleList.add(svgCircle);
                addToListAndSetId(circleList, svgCircle);
            } else if(shape instanceof  SVGEcliplse){
                SVGEcliplse ecliplse = (SVGEcliplse) shape;
                ecliplseList.add(ecliplse);
                addToListAndSetId(ecliplseList, ecliplse);
            }
        }
    }

    // This does not force both params to be of same type 
    public static void addToListAndSetId(List<SVGShape> shapeList, SVGShape shape) {
        shapeList.add(shape);
        if(shape instanceof SVGCircle) {
              shape.setId("some-circle-id");
        } else if(shape instanceof  SVGEcliplse) {
              shape.setId("some-eclipse-id");
        }
    }

    // This DOES force both params (shapelist type and shape type) to be of same type 
    public <T extends SVGShape> void addToListAndSetId2(List<T> shapeList, T shape) {
        shapeList.add(shape);
        shape.setId("some-id");
    }


public class SVGCircle extends SVGShape {
}

public class SVGEcliplse extends SVGShape {
}

public class SVGShape implements ISVGShape {
    public void setId(String id) {
        // some logic
    }
}

public interface ISVGShape {
}