参数类型窄化的高效方式选择及Complex类set方法实现咨询
参数类型窄化的高效方式选择及Complex类set方法实现咨询
看起来你在设计复数类体系的set方法时,卡在了两种实现方式的选择上,我来帮你拆解下这两个方案的优劣,顺便提些实际开发里的小建议~
首先明确你的场景:你是在Cartesian.Float类里实现set方法,要接收任意Complex子类实例(不管是极坐标还是笛卡尔坐标、单精度还是双精度),最终把值转成自己的单精度笛卡尔坐标格式。我们先对比你给出的两个实现:
第一个方案:用局部变量存储转换结果
public void set(Complex z) { Cartesian.Double z2 = toCartesian(z); re = (float) z2.re; im = (float) z2.im; }
这个方案我个人更推荐,原因有这几点:
- 可读性拉满:局部变量
z2明明白白标注了类型是Cartesian.Double,谁看代码都能立刻get到这是已经转好格式的双精度笛卡尔复数,不用反复回忆“哦对,参数z现在已经被转类型了” - 减少冗余操作:转换逻辑只在
toCartesian里做一次,后续直接访问z2的属性就行,不用重复写强制类型转换的代码 - 可维护性更强:如果以后你需要用到转换后实例的其他属性,或者调整转换逻辑,直接基于
z2修改就行,不用到处加强转代码
第二个方案:重新赋值参数后重复强转
public void set(Complex z) { z = toCartesian(z); re = (float) ((Cartesian.Double) z).re; im = (float) ((Cartesian.Double) z).im; }
这个方案的问题就很明显了:
- 代码冗余,要重复写
((Cartesian.Double) z)的强转逻辑,虽然编译器可能会做优化缓存强转结果,但写起来麻烦,读起来也费劲 - 万一后面要加更多属性(比如实部虚部以外的衍生属性),还要不断重复强转,容易写错
额外要提醒你的bug修复点
你当前的toCartesian方法有个隐藏的坑:如果传入的是Cartesian.Float实例,直接强转((Cartesian.Double) z)会抛出ClassCastException!因为Cartesian.Float和Cartesian.Double是平级的子类关系,不是继承关系。建议你把toCartesian改成这样,兼容所有笛卡尔坐标的子类:
public static Cartesian.Double toCartesian(Complex z) { if (z instanceof Polar) { double module = z.getModule(); double angle = z.getAngle(); return new Cartesian.Double(Math.cos(angle) * module, Math.sin(angle) * module); } else if (z instanceof Cartesian) { Cartesian<?> cartesian = (Cartesian<?>) z; // 建议在Cartesian抽象类里加getReAsDouble()和getImAsDouble()方法,子类自己实现精度转换 return new Cartesian.Double(cartesian.getReAsDouble(), cartesian.getImAsDouble()); } else { throw new IllegalArgumentException("不支持的Complex类型"); } }
这样不管是Cartesian.Float还是Cartesian.Double,都能安全转成Cartesian.Double,不会炸。
进阶优化建议
如果想进一步减少精度损失(毕竟先转双精度再转单精度会多一次转换),你可以重载一个toCartesianFloat方法,直接把任意Complex转成Cartesian.Float:
public static Cartesian.Float toCartesianFloat(Complex z) { if (z instanceof Polar) { double module = z.getModule(); double angle = z.getAngle(); return new Cartesian.Float((float)(Math.cos(angle) * module), (float)(Math.sin(angle) * module)); } else if (z instanceof Cartesian.Double) { Cartesian.Double cd = (Cartesian.Double) z; return new Cartesian.Float((float) cd.re, (float) cd.im); } else if (z instanceof Cartesian.Float) { return (Cartesian.Float) z; } else { throw new IllegalArgumentException("不支持的Complex类型"); } }
这样你的Cartesian.Float的set方法就能直接用这个方法,一步到位转成单精度,既高效又减少精度损耗:
public void set(Complex z) { Cartesian.Float z2 = toCartesianFloat(z); re = z2.re; im = z2.im; }
总的来说,优先选第一个方案,先把toCartesian的bug修了,再根据需求考虑进阶的精度优化就好~
内容来源于stack exchange
相关产品推荐
相关产品推荐

