接口中的嵌套参数化类型
Nested Parameterized types in interface
我有以下接口:
CacheKey接口:
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
缓存值接口:
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
缓存接口:
public interface Cache<CacheKey<K extends Serializable>, CacheValue<V extends Serializable>> {
}
缓存接口无法编译。我得到的错误是:
[13,35] > 预期
即在 CacheKey 编译器不喜欢另一个左尖括号之后:
public interface Cache<CacheKey<
^
这在 Java 中是不可能的吗?
您在这里错过了关键的一步:实施。
通常在实现中您要定义 ? extends Serializable
的类型。您不需要在 Cache
接口中实现它。
接口只需要知道它的泛型类型是什么,而不是它们的子代的泛型:这是为了实现。
看看下面的示例,了解我的确切意思。
补充:当您定义类似 Cache<CacheKey, CacheValue>
的内容时,您并不是在指代 class,而是在创建通用别名。 CacheKey
可以很容易地替换为 Blabla
并继续具有相同的行为。解决方案是使用 extends
来确保我们谈论的是类型。
这也是 Cache<CacheKey<...>>
没有编译的原因,因为 CacheKey
不是指 class 而是用作别名
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
public interface Cache<K extends CacheKey<? extends Serializable>, V extends CacheValue<? extends Serializable>> {
void put(K key, V value);
}
public class CacheImpl implements Cache<CacheKey<String>, CacheValue<String>> {
@Override
public void put(CacheKey<String> key, CacheValue<String> value) {
// do whatever
}
}
按照其他答案中的建议,使用 wildcard-bounded 泛型类型并不是一个好主意。
如果您这样声明 class:
public interface Cache<K extends CacheKey<?>, V extends CacheValue<?>> {
}
那么您将永远无法有效地调用键或值上的 get()
,因为它们只会 return Serializable
。 Serializable
是一个 没用的 class (它与 Object
实际上在你的代码中几乎没有什么不同)。
相反,我会简单地声明 class,例如:
public interface Cache<K extends Serializable, V extends Serializable> {
然后声明 put
方法接受一个 CacheKey<K>
和一个 CacheValue<V>
:
void put(CacheKey<K> key, CacheValue<V> value);
因为,最终,CacheKey<K>
和 CacheValue<V>
的所有实现都应该是无法区分的。
如果你真的想要强制CacheKey<K>
和CacheValue<V>
为特定类型,你需要添加更多类型变量:
public interface Cache<
K extends Serializable, CK extends CacheKey<K>,
V extends Serializable, CV extends CacheValue<V>> {
void put(CK key, CV value);
}
但这真的很恶心,因为无论你在哪里直接使用 Cache
类型,你都必须携带所有这 4 个类型变量。
当然,您可以专门化接口来隐藏其中一些类型变量:
interface StringKey extends CacheKey<String> {}
interface IntegerValue extends CacheValue<Integer> {}
interface StringIntegerCache extends Cache<String, StringKey, Integer, IntegerValue> {}
然后只需使用 StringIntegerCache
。这样做的用处取决于您的应用程序。
我有以下接口:
CacheKey接口:
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
缓存值接口:
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
缓存接口:
public interface Cache<CacheKey<K extends Serializable>, CacheValue<V extends Serializable>> {
}
缓存接口无法编译。我得到的错误是: [13,35] > 预期
即在 CacheKey 编译器不喜欢另一个左尖括号之后:
public interface Cache<CacheKey<
^
这在 Java 中是不可能的吗?
您在这里错过了关键的一步:实施。
通常在实现中您要定义 ? extends Serializable
的类型。您不需要在 Cache
接口中实现它。
接口只需要知道它的泛型类型是什么,而不是它们的子代的泛型:这是为了实现。
看看下面的示例,了解我的确切意思。
补充:当您定义类似 Cache<CacheKey, CacheValue>
的内容时,您并不是在指代 class,而是在创建通用别名。 CacheKey
可以很容易地替换为 Blabla
并继续具有相同的行为。解决方案是使用 extends
来确保我们谈论的是类型。
这也是 Cache<CacheKey<...>>
没有编译的原因,因为 CacheKey
不是指 class 而是用作别名
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
public interface Cache<K extends CacheKey<? extends Serializable>, V extends CacheValue<? extends Serializable>> {
void put(K key, V value);
}
public class CacheImpl implements Cache<CacheKey<String>, CacheValue<String>> {
@Override
public void put(CacheKey<String> key, CacheValue<String> value) {
// do whatever
}
}
按照其他答案中的建议,使用 wildcard-bounded 泛型类型并不是一个好主意。
如果您这样声明 class:
public interface Cache<K extends CacheKey<?>, V extends CacheValue<?>> {
}
那么您将永远无法有效地调用键或值上的 get()
,因为它们只会 return Serializable
。 Serializable
是一个 没用的 class (它与 Object
实际上在你的代码中几乎没有什么不同)。
相反,我会简单地声明 class,例如:
public interface Cache<K extends Serializable, V extends Serializable> {
然后声明 put
方法接受一个 CacheKey<K>
和一个 CacheValue<V>
:
void put(CacheKey<K> key, CacheValue<V> value);
因为,最终,CacheKey<K>
和 CacheValue<V>
的所有实现都应该是无法区分的。
如果你真的想要强制CacheKey<K>
和CacheValue<V>
为特定类型,你需要添加更多类型变量:
public interface Cache<
K extends Serializable, CK extends CacheKey<K>,
V extends Serializable, CV extends CacheValue<V>> {
void put(CK key, CV value);
}
但这真的很恶心,因为无论你在哪里直接使用 Cache
类型,你都必须携带所有这 4 个类型变量。
当然,您可以专门化接口来隐藏其中一些类型变量:
interface StringKey extends CacheKey<String> {}
interface IntegerValue extends CacheValue<Integer> {}
interface StringIntegerCache extends Cache<String, StringKey, Integer, IntegerValue> {}
然后只需使用 StringIntegerCache
。这样做的用处取决于您的应用程序。