如何将实现多接口的对象转换为继承多接口的自定义接口类型?
嘿,我太懂你遇到的这个困扰了!明明MappingIterator已经实现了Iterator和Closeable这两个接口,我们自己定义的CloseableIterator也只是继承了这两个接口,逻辑上完全兼容,但编译器就是卡着不让过,还要加unchecked转换,确实挺闹心的。
给你两个实用的解决方案,都是类型安全且能解决编译问题的:
方案一:用适配器模式(最规范安全的方式)
这种方式完全符合面向接口编程的原则,彻底隐藏Jackson的具体实现类,还能保证类型安全,没有任何警告。我们只需要写一个简单的适配器类,把MappingIterator包装起来,实现自己的CloseableIterator接口:
import java.io.IOException; import com.fasterxml.jackson.databind.MappingIterator; public class MappingIteratorAdapter<T> implements CloseableIterator<T> { private final MappingIterator<T> delegate; public MappingIteratorAdapter(MappingIterator<T> delegate) { this.delegate = delegate; } @Override public boolean hasNext() { return delegate.hasNext(); } @Override public T next() { return delegate.next(); } @Override public void close() throws IOException { delegate.close(); } // 可选:如果需要支持Iterator的remove方法,可实现该方法 @Override public void remove() { delegate.remove(); } }
然后在业务方法里返回这个适配器实例就行:
CloseableIterator<FooBar> readFooBars(...) { return new MappingIteratorAdapter<>(objectMapper.readValues(...)); }
方案二:用泛型约束的工具方法消除警告
如果你不想写完整的适配器类,也可以用一个泛型工具方法帮编译器理清类型关系,这样就能合法转换,而且只需要在工具方法里加一次安全的SuppressWarnings,业务代码里干干净净:
// 私有工具方法,用泛型约束明确传入对象的类型特性 @SuppressWarnings("unchecked") private static <T, I extends Iterator<T> & Closeable> CloseableIterator<T> castToCloseableIterator(I iterator) { return (CloseableIterator<T>) iterator; } // 业务方法里直接调用工具方法 CloseableIterator<FooBar> readFooBars(...) { return castToCloseableIterator(objectMapper.readValues(...)); }
这里的泛型约束I extends Iterator<T> & Closeable会告诉编译器:传入的iterator肯定同时实现了Iterator和Closeable接口,这样转换为CloseableIterator<T>就是类型安全的,这个@SuppressWarnings完全是安全的,不会有潜在的类型问题。
为什么原来的直接转换不行?
这里得给你解释下根源:Java是名义类型系统,不是结构类型系统。也就是说,哪怕两个类型的结构完全一致(比如MappingIterator实现了Iterator+Closeable,CloseableIterator继承了Iterator+Closeable),只要MappingIterator没有显式声明implements CloseableIterator,编译器就不会认为它们是兼容的类型。所以你直接返回的话,编译器只能给你一个unchecked转换的警告,因为它没法在编译时确认这个转换是绝对安全的(虽然我们知道运行时肯定没问题)。
备注:内容来源于stack exchange,提问作者Joseph

