努力掌握泛型。我有一个父类"Unit",它由子类"FootAndInch","Mm"和"Inch"扩展。
所有子类共享一些算术运算:加、减、除、乘等......因此应用泛型并希望编码一次而不是将代码复制到所有三个子类中是有意义的。
我假设最好的地方是在父类"Unit"中:
public class Unit<T> {
BigDecimal value;
public Unit(BigDecimal value) {
this.value = value;
}
public BigDecimal getValue() {
return value;
}
// First Arithmetic operation
public <T extends Unit> T add(T measurement) {
return value.add(measurement.getValue());
}
}
然后的想法是能够将相同的测量值加在一起:
Mm value1 = new Mm(20);
Mm value2 = new Mm(40);
Mm result1 = value1.add(value2);
Inch value3 = new Inch(4);
Inch value4 = new Inch(7);
Inch result2 = value3.add(value4);
不幸的是,我从类单位中的"add"方法收到错误:"不兼容的类型:BigDecimal 无法转换为 T">
这是有道理的,但我不确定如何返回类型 T
你选择了一个粗糙的例子,它需要使用自引用类型。
以下内容按预期编译和运行:
public class Unit<T extends Unit<T>> {
BigDecimal value;
public Unit(BigDecimal value) {
this.value = value;
}
public BigDecimal getValue() {
return value;
}
// First Arithmetic operation
public <U extends Unit<U>> U add(U measurement) {
value = value.add(measurement.getValue());
return (U)this;
}
}
public class MM extends Unit<MM> {
public MM(BigDecimal value) {
super(value);
}
}
public static void main (String[] args) {
MM mm1 = new MM(BigDecimal.ONE);
MM mm2 = new MM(BigDecimal.TEN);
MM mm3 = mm1.add(mm2);
System.out.println(mm3.getValue()); // 11
}
观看现场演示。
有趣的部分是:
- 类型引用自身,因此当 T 扩展 Unit 时,子类可以被 T 捕获
- BigDecimal 是不可变的。调用其
add()
方法对它没有任何作用;而是将结果作为新的 BigDecimal 返回 - add(( 的返回需要一个强制转换
首先,你有一个类型参数T
在类级别,T extends Unit
在方法级别。 这些是不同的T
。 如果您真的需要两者,明智的做法是给它们起不同的名字。 但我的猜测是类级别的类型参数不应该存在,因为T extends Unit
您使用的是原始类型Unit
(即没有类型参数(。
其次,您的Unit
类和子类不仅表示单位本身,还表示特定单位中的值。 除了命名问题之外,您还应该考虑是否真的需要这些类型,或者可以只使用一个类型Measurement
,该类型将其内部值存储在 mm 中,但具有静态工厂方法,例如
static Measurement ofInches(BigDecimal inches) {...}
static Measurement ofFeetAndInches(BigDecimal feet, BigDecimal inches) {...}
等,使用正确转换为内部 mm 值来构建Measurement
。 然后,add
方法只需对内部值求和即可。 这正是java.time.Duration
类采用的方法,该类具有静态方法ofDays(long days)
,ofHours(long hours)
等,并且具有对内部值求和的方法plus(Duration duration)
(为了精度而分为秒和纳米,但这无关紧要(。 它还具有toDays()
,toHours()
等转换为不同单位的方法。