背景:
我正在尝试实现一个小模板,即泛型类,这将允许我实现如下的传递引用功能。
public static class Ref<T> {
T value;
public Ref(T InitValue) { this.set(InitValue); }
public void set(T Value) { this.value = Value; }
public T get() { return this.value; }
}
所以,我可以定义一个带有&#39; Ref&#39;实际可以改变价值的地方,例如
public static void function(Ref<Byte> x)
{
x.set((byte)0x7E);
}
通过引用传递的变量的初始化看起来不那么优雅。
Ref<Byte> to_be_changed = new Ref<Byte>((byte)0);
...
function(to_be_changed);
...
Byte result = to_be_changed.get()
问题:
Java有没有办法做得更好?构造函数可以直接初始化&#39; 0&#39;根据与包装类型相关的原始类型,它作为模板类型传递?我喜欢
...
public Ref() { this.value = (T.relatedPrimitiveClass())0; }
...
其中Integer.relatedPrimitiveClass()
将提供int
; Byte.relatedPrimitiveClass()
发送byte
。
答案 0 :(得分:1)
首先,最重要的是要理解java泛型不是模板。泛型是在类型上参数化的类/接口。我建议从oracle阅读泛型教程:https://docs.oracle.com/javase/tutorial/java/generics/types.html
可以使用反射来获取Ref类的参数化类型T,并使用它来确定默认construtor的初始值,但我不建议这样做。
您可以为类型创建子类,而不是反射,这需要默认构造函数(例如基元的对象版本):
public static class ByteRef extends Ref<Byte> {
public ByteRef() {
super((byte)0);
}
public ByteRef(byte value) {
super(value);
}
// I'm not sure, if I like this one :-)
public void set(int value) {
super.set((byte)value);
}
}
除了子类化,您还可以向Ref class添加新方法:
public static class Ref<T> {
T value;
public Ref(T initValue) {
this.set(initValue);
}
public void set(T Value) {
this.value = Value;
}
public T get() {
return this.value;
}
public static Ref<Byte> createByteRef() {
return new Ref<Byte>((byte)0);
}
public static Ref<Byte> createByteRef(byte value) {
return new Ref<Byte>(value);
}
}
或者您可以创建单独的工厂类: 公共类Refs { public static Ref createByteRef(){ return new Ref((byte)0); }
public static Ref<Byte> createByteRef(byte value) {
return new Ref<Byte>(value);
}
}
最后一个选项是使用反射来获取参数化类型。我个人不会使用这个解决方案,因为基本类的数量是有限的,你可以选择用子类创建更整洁的接口
public abstract static class PrimitiveNumberRef<T extends Number> extends
Ref<T> {
private Class<T> type;
public PrimitiveNumberRef() {
// This requires default constructor for Ref class
type = getGenericType(getClass());
super.set((T) getInitialValue(type));
}
@Override
public void set(T value) {
if (value == null) {
throw new IllegalArgumentException(
"Null value is not allowed for PrimitiveNumerRef type: "
+ type);
}
if (!type.isInstance(value)) {
throw new IllegalArgumentException("Unsupported value type: "
+ value.getClass());
}
super.set(value);
}
@SuppressWarnings("unchecked")
private static <T> Class<T> getGenericType(Class<?> clz) {
return (Class<T>) ((ParameterizedType) clz.getGenericSuperclass())
.getActualTypeArguments()[0];
}
private static <T> T getInitialValue(Class<T> clz) {
if (clz == Byte.class) {
return clz.cast((byte) 0);
} else if (clz == Short.class) {
return clz.cast((short) 0);
} else if (clz == Integer.class) {
return clz.cast((int) 0);
} else if (clz == Double.class) {
return clz.cast((double) 0);
} else if (clz == Float.class) {
return clz.cast((float) 0);
} else if (clz == Long.class) {
return clz.cast((long) 0);
} else {
throw new IllegalArgumentException("Unsupported type: "
+ clz.getName());
}
}
}
PrimitiveNumberRef实例化如下:
Ref<Long> val1 = new PrimitiveNumberRef<Long>() { };