想象一下这样的代码:
public class Value<T> {
private T value;
public Value(T value) {
this.value = value;
}
public int size() {
return sizeOf(value);
}
private int sizeOf(int value) {
return Integer.BYTES;
}
private int sizeOf(String value) {
return value.length() * Character.BYTES;
}
}
和某处(例如main
)
Value<String> value = new Value<String>("hello");
问题是代码无法编译,因为我没有实现sizeOf(T value)
,但是我不明白为什么编译器会抱怨---它看到我只使用它<T=String>
即可。如果我实现通用sizeOf(T value)
,它将优先(如此处Java generics (template) specialization possible (overriding template types with specific types)所述)
请注意,那里提出的解决方案(具有StringValue
子类)在我的情况下并不真正适用,因为我已经有一些我正在使用的子类,所以我需要创建许多额外的类(按类型划分的次数)
但我更喜欢更直接的东西,比如这个
答案 0 :(得分:2)
你必须声明sizeOf(T value)
因为T
可以是任何类型,所以为了维护类型controll,编译器需要&#34;通用&#34; sizeOf
方法的版本,可以预示任何可能的类型。
想想如果你会使用类似new Value<List<Object>>(new ArrayList<Object>).size()
之类的东西会发生什么 - 当你没有专门用于返回集合大小的方法时会发生什么?
问题是,在运行时,泛型类型被删除,因此JVM不知道应该使用重载方法。在此处查看有关类型擦除的更多信息。 https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
答案 1 :(得分:2)
无法为size()
提供实施。你的代码是双重调度模式的一半,但是一直无法进行,因为你无法要求像String这样的类型来实现size()
。
一种方法是在构造上要求尺寸代码:
public class Value<T> {
private T value;
private Function<T, Integer> size;
public Value(T value, Function<T, Integer> size) {
this.value = value;
this.size;
}
public int size() {
return size.apply(value);
}
}
例如创建Value<String>
:
Value<String> val = new Value("foo", s -> s.length() * Character.BYTES)
或者如果不起作用,请对支持的类型使用instanceof
:
public int size() {
if (value instanceof Integer)
return Integer.BYTES;
if (value instanceof String)
return ((String)value).length() * Character.BYTES;
// other supported types
throw new IllegalStateException();
}