Java 未选中从包含通配符的列表转换为特定类型的列表

Java Unchecked Cast from List containing wildcard to List of a specific type

提问人:mepmerp 提问时间:11/9/2022 更新时间:11/10/2022 访问量:117

问:

我有以下课程

public class PathPart {
    private final String pathPart;

    public PathPart(String pathPart) {
        this.pathPart = pathPart;
    }

    public String getPathPart() {
        return pathPart;
    }
}

public class Path {
    private final List<? extends PathPart> pathParts;

    public Path(String path) {
        this.pathParts = getPathParts(path);
    }

    public List<? extends PathPart> getPathParts() {
        return this.pathParts;
    }

    protected List<? extends PathPart> getPathParts(String path) {
        return Arrays.stream(path.split("/")).map(PathPart::new).collect(Collectors.toList());
    }
}

public class FooBarPathPart extends PathPart {
    public FooBarPathPart(String pathPart) {
        super(isFoo(pathPart) ? "bar" : pathPart);
    }

    private static boolean isFoo(String pathPart) {
        return "foo".equals(pathPart);
    }
}


public class FooBarPath extends Path {
    public FooBarPath(String path) {
        super(path);
    }

    @Override
    public List<FooBarPathPart> getPathParts() {
        // UNCHECKED CAST HERE
        return (List<FooBarPathPart>) super.getPathParts();
    }

    @Override
    protected List<FooBarPathPart> getPathParts(String path) {
        return Arrays.stream(path.split("/")).map(FooBarPathPart::new).collect(Collectors.toList());
    }
}

我想在我的对象中捕获文件系统路径的结构,该路径将 、 、 、 每个存储为一个对象。/my/path/to/a/directoryPathmypathtoadirectoryPathPart

现在,我有一个子类 called ,其中如果路径部分等于 ,那么我希望它更改为 。而且,我还有 which 是 的子类,它存储了 的列表。所以本质上会成为PathPartFooBarPathPartfoobarFooBarPathPathFooBarPathPart/my/path/to/foo/directory/my/path/to/bar/directory

我的问题是我在类中的方法中收到来自 to 的警告。Unchecked castList<? extends PathPart>List<FooBarPath>getPathParts()FooBarPath

有没有办法正确摆脱这种未经检查的投射警告?我在这里使用通配符是否正确?或者有没有更好的方法来解决这个问题而不涉及通配符?我对泛型不是很熟悉

Java 泛型 警告通 配符 未选中强制转换

评论

2赞 Thomas 11/9/2022
我会这样做:和.如果不是泛型的,则不能在没有任何强制转换的情况下进行转换,因为除了列表包含元素(或任何子类)之外,不会有任何信息。class Path<T extends PathPart> { private final List<T> pathParts; ... }class FooBarPath extends Path<FooBarPathPath>{ ... }PathpathPartsPathPart
0赞 mepmerp 11/9/2022
谢谢这是有道理的,但是我在尝试创建我希望创建对象的列表并让里面的方法实际创建对象列表时遇到了麻烦。这可能吗?return Arrays.stream(path.split("/")).map(PathPart::new).collect(Collectors.toList());Pathnew Path("/some/path")PathPart
1赞 Thomas 11/10/2022
有一些方法使用反射,但我可能会选择抽象的通用实现,然后成为兄弟姐妹,或者,或者,为构造函数提供创建者函数,例如通过工厂方法。PathFooBarPath

答:

0赞 mepmerp 11/10/2022 #1

感谢托马斯的帮助

我已经使用泛型和创建者函数解决了这个问题。以下是完整的解决方案:

public class PathPart {
    private final String pathPart;

    public PathPart(String pathPart) {
        this.pathPart = pathPart;
    }

    public String getPathPart() {
        return pathPart;
    }
}

public class FooBarPathPart extends PathPart {
    public FooBarPathPart(String pathPart) {
        super(isFoo(pathPart) ? "bar" : pathPart);
    }

    private static boolean isFoo(String pathPart) {
        return "foo".equals(pathPart);
    }
}

public abstract class AbstractPath<T extends PathPart> {
    private final List<T> pathParts;
    private final Function<String, T> factory;

    public AbstractPath(Function<String, T> factory, String path) {
        this.factory = factory;
        this.pathParts = createPathParts(path);
    }

    public List<T> createPathParts() {
        return this.pathParts;
    }

    private List<T> createPathParts(String path) {
        return Arrays.stream(path.split("/")).map(factory).collect(Collectors.toList());
    }
}

public class Path extends AbstractPath<PathPart> {
    public Path(String path) {
        super(PathPart::new, path);
    }
}

public class FooBarPath extends AbstractPath<FooBarPathPart> {
    public FooBarPath(String path) {
        super(FooBarPathPart::new, path);
    }
}