Java三角形类复制构造函数空引用拷贝测试失败求助
复制构造函数测试失败问题排查
问题背景
学习中级Java课程,需实现一个封装的三角形类,核心要求包括:
- 验证给定边长是否构成有效三角形(边长为正且满足三角不等式)
- 实现复制构造函数:
Triangle(Triangle triangle),复制传入对象的实例变量;若传入引用为null,则用DEFAULT_SIDE初始化所有边长
当前复制构造函数在空引用测试中失败,测试提示:"Copy of null ==> expected: <1.0> but was: <0.0>"
现有复制构造函数代码
public Triangle(Triangle triangle) { Triangle newTriangle = new Triangle(); if (triangle != null) { if (isTriangle(triangle.getSideA(), triangle.getSideB(), triangle.getSideC())) { newTriangle.setSideA(triangle.getSideA()); newTriangle.setSideB(triangle.getSideB()); newTriangle.setSideC(triangle.getSideC()); } } else { newTriangle.setSideA(DEFAULT_SIDE); newTriangle.setSideB(DEFAULT_SIDE); newTriangle.setSideC(DEFAULT_SIDE); } }
测试代码片段
@Test void testCopyConstructor() { // Test invalid input. Triangle triangle = null; Triangle copy = new Triangle(triangle); double[] expected = {1, 1, 1}; String msg = "Copy of null"; checkSides(copy, expected, msg); // ... 其他测试代码 }
完整Triangle类代码
public class Triangle { private double sideA; private double sideB; private double sideC; public final static String POLYGONSHAPE = "Triangle"; public final static double DEFAULT_SIDE = 1; //CONSTRUCTORS public Triangle() { this.sideA = DEFAULT_SIDE; this.sideB = DEFAULT_SIDE; this.sideC = DEFAULT_SIDE; } public Triangle(double sideA, double sideB, double sideC) { if (isTriangle(sideA,sideB,sideC)) { this.sideA = sideA; this.sideB = sideB; this.sideC = sideC; } else { sideA = DEFAULT_SIDE; sideB = DEFAULT_SIDE; sideC = DEFAULT_SIDE; } } public Triangle(double[] sides) { this(); if (isTriangle(sides)) { this.sideA = sides[0]; this.sideB = sides[1]; this.sideC = sides[2]; } else { this.sideA = DEFAULT_SIDE; this.sideB = DEFAULT_SIDE; this.sideC = DEFAULT_SIDE; } } public Triangle(Triangle triangle) { Triangle newTriangle = new Triangle(); if (triangle != null) { if (isTriangle(triangle.getSideA(), triangle.getSideB(), triangle.getSideC())) { newTriangle.setSideA(triangle.getSideA()); newTriangle.setSideB(triangle.getSideB()); newTriangle.setSideC(triangle.getSideC()); } } else { newTriangle.setSideA(DEFAULT_SIDE); newTriangle.setSideB(DEFAULT_SIDE); newTriangle.setSideC(DEFAULT_SIDE); } } //SIDE GETTERS public double getSideA() { return sideA; } public double getSideB() { return sideB; } public double getSideC() { return sideC; } public double[] getSides() { double[] sides = {sideA, sideB, sideC}; return sides; } //ANGLE GETTERS public double getAngleA() { double angleA = lawOfCosines(sideB, sideC, sideA); return angleA; } public double getAngleB() { double angleB = lawOfCosines(sideC, sideA, sideB); return angleB; } public double getAngleC() { double angleC = lawOfCosines(sideA, sideB, sideC); return angleC; } public double[] getAngles() { return new double[] {getAngleA(), getAngleB(), getAngleC()}; } //SIDE SETTERS public boolean setSideA(double sideA) { if (isTriangle(sideA, sideB, sideC)) { this.sideA = sideA; return true; } else { return false; } } public boolean setSideB(double sideB) { if (isTriangle(sideA, sideB, sideC)) { this.sideB = sideB; return true; } else { return false; } } public boolean setSideC(double sideC) { if (isTriangle(sideA, sideB, sideC)) { this.sideC = sideC; return true; } else { return false; } } public boolean setSides(double[] sides) { if (isTriangle(sides)) { this.sideA = sides[0]; this.sideB = sides[1]; this.sideC = sides[2]; return true; } else { return false; } } //HELPER METHODS public static boolean isTriangle(double a, double b, double c) { //check if sides are positive if (a > 0 && b > 0 && c > 0) { //check if they satisfy triangle inequality if ((a + b) > c && (a + c) > b && (b + c) > a) { return true; } else { return false; } } else { return false; } } public static boolean isTriangle(double[] sides) { if (sides == null || sides.length != 3 || sides[0] <= 0 || sides[1] <= 0 || sides[2] <= 0 || sides[0] + sides[1] <= sides[2] || sides[0] + sides[2] <= sides[1] || (sides[1] + sides[2]) <= sides[0]) { return false; } else { return true; } } public static double lawOfCosines(double a, double b, double c) { double angle; //find angle in radians angle = Math.toDegrees(Math.acos((Math.pow(b, 2) + Math.pow(a, 2) - Math.pow(c, 2))/(2.0 * a * b))); return angle; } public String toString() { String output = String.format("%s(%.4f, %.4f, %.4f)", POLYGONSHAPE, this.sideA, this.sideB, this.sideC); return output; } }
问题根源
- 核心错误:复制构造函数中创建了局部对象
newTriangle并对其赋值,但完全没有初始化当前对象(this)的成员变量。Java中成员变量默认值为0.0,所以测试获取到的边长是0.0而非预期的1.0。 - 额外逻辑偏差:原代码中额外添加了
isTriangle验证,但需求明确要求直接复制传入对象的实例变量,无需二次验证有效性。 - 其他潜在问题:三参数构造函数的else分支中,未使用
this前缀,导致赋值给了局部参数而非成员变量,会引发类似的默认值问题。
修正方案
修正后的复制构造函数
public Triangle(Triangle triangle) { if (triangle != null) { // 直接复制传入对象的成员变量,遵循需求要求 this.sideA = triangle.getSideA(); this.sideB = triangle.getSideB(); this.sideC = triangle.getSideC(); } else { // 传入null时用默认值初始化当前对象 this.sideA = DEFAULT_SIDE; this.sideB = DEFAULT_SIDE; this.sideC = DEFAULT_SIDE; } }
修正三参数构造函数的else分支
public Triangle(double sideA, double sideB, double sideC) { if (isTriangle(sideA,sideB,sideC)) { this.sideA = sideA; this.sideB = sideB; this.sideC = sideC; } else { // 添加this前缀,赋值给成员变量 this.sideA = DEFAULT_SIDE; this.sideB = DEFAULT_SIDE; this.sideC = DEFAULT_SIDE; } }
验证要点
- 测试空引用场景:确认新对象的边长均为
DEFAULT_SIDE(1.0) - 测试有效三角形复制:确认新对象与原对象边长完全一致
- 测试无效三角形复制:确认新对象复制原对象的无效边长(若需求允许)
内容的提问来源于stack exchange,提问作者Aly
相关产品推荐
相关产品推荐

