Java泛型疑问:为何编译器无法推断ArchiveStreamHolder的类型参数?
你的代码里编译器没法推断类型参数,核心原因是静态方法of的泛型约束和分支返回的具体类型无法统一匹配,具体来说:
泛型约束的冲突
你定义的ArchiveStreamHolder<T extends ArchiveOutputStream<E>, E extends ArchiveEntry>要求T绑定到某个特定E类型的ArchiveOutputStream子类,但ZipArchiveOutputStream对应的Entry是ZipArchiveEntry,TarArchiveOutputStream对应的是TarArchiveEntry——这两个分支的T和E完全是不同的类型组合。而of方法的返回类型要求是单一的ArchiveStreamHolder<T,E>,编译器找不到能同时覆盖两个分支的通用T和E,自然无法推断。菱形运算符缺少上下文提示
你在new ArchiveStreamHolder<>(...)里用了菱形运算符,但由于方法本身的泛型约束存在歧义,没有明确的上下文告诉编译器应该用哪种T和E,进一步加剧了推断失败的问题。
解决方法
方法一:简化泛型约束(推荐,适合大多数场景)
如果你的业务逻辑不需要直接操作E类型的Entry,可以把E的泛型约束用通配符替代,让T只需要是任意ArchiveEntry对应的ArchiveOutputStream子类:
import java.io.OutputStream; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; public class ArchiveStreamHolder<T extends ArchiveOutputStream<? extends ArchiveEntry>> { final T archiveStream; private ArchiveStreamHolder(T archiveStream) { this.archiveStream = archiveStream; } public static <T extends ArchiveOutputStream<? extends ArchiveEntry>> ArchiveStreamHolder<T> of(OutputStream os, boolean zip) { if (zip) { return new ArchiveStreamHolder<>(new ZipArchiveOutputStream(os)); } else { return new ArchiveStreamHolder<>(new TarArchiveOutputStream(os)); } } }
这样两个分支的类型都符合T extends ArchiveOutputStream<? extends ArchiveEntry>的约束,编译器能正常推断出通用类型。
方法二:拆分静态方法(需要明确操作Entry类型时用)
如果必须保留E的泛型绑定,可以把of拆成两个独立的静态方法,分别处理Zip和Tar的情况,让每个方法的类型参数明确无歧义:
import java.io.OutputStream; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; public class ArchiveStreamHolder<T extends ArchiveOutputStream<E>, E extends ArchiveEntry> { final T archiveStream; private ArchiveStreamHolder(T archiveStream) { this.archiveStream = archiveStream; } public static ArchiveStreamHolder<ZipArchiveOutputStream, ZipArchiveEntry> zip(OutputStream os) { return new ArchiveStreamHolder<>(new ZipArchiveOutputStream(os)); } public static ArchiveStreamHolder<TarArchiveOutputStream, TarArchiveEntry> tar(OutputStream os) { return new ArchiveStreamHolder<>(new TarArchiveOutputStream(os)); } }
调用时直接用ArchiveStreamHolder.zip(os)或ArchiveStreamHolder.tar(os),编译器能精准推断每个方法的类型参数。
内容的提问来源于stack exchange,提问作者komen

