本文详细介绍了在Java中遍历对象数组,查找特定类型(如UAV)的最昂贵和最便宜实例的正确方法。通过区分并独立跟踪对象的实际价格和其在数组中的索引,并恰当初始化比较变量,可以避免常见的逻辑错误,确保准确地识别出满足条件的最大和最小值对象。
1. 问题描述
在面向对象编程中,我们经常需要处理包含多种对象类型的数组。一个常见需求是从这些数组中找出满足特定条件(例如,最昂贵或最便宜)的特定类型对象。例如,在一个 FlyingObjects 数组中,我们可能需要找出其中所有 UAV(无人机)对象里价格最高和最低的实例。
初始尝试时,开发者可能会遇到一个常见问题:比较逻辑错误地将对象的价格与数组索引混淆,或者初始化比较变量的方式不当,导致结果总是返回数组中的第一个或最后一个匹配项,而非真正的最大或最小值。
2. 错误的实现逻辑分析
考虑以下不正确的代码片段,它试图找出最昂贵和最便宜的 UAV:
public static void findLeastAndMostExpensiveUAV(FlyingObjects[] flyingObjects) { int mostExpensive = -1; // 试图用一个int变量同时表示索引和价格(不合理) int leastExpensive = 1000000000; // 试图用一个int变量同时表示索引和价格(不合理) boolean hasUav = false; if(flyingObjects == NULL) { System.out.println("There is no UAV"); return; // 添加return防止后续NullPointerException } for(int i = 0; i < flyingObjects.length; i++) { if (flyingObjects[i] instanceof Uav) { Uav a = (Uav) flyingObjects[i]; // 错误:将对象的价格 (double) 与用于存储索引的int变量进行比较 if (a.getPrice() >= mostExpensive) { // mostExpensive此时是索引值,不是价格 mostExpensive = i; // 错误:将索引赋值给mostExpensive,但它之前用于价格比较 } if (a.getPrice() <= leastExpensive){ // leastExpensive此时是索引值,不是价格 leastExpensive = i; // 错误:将索引赋值给leastExpensive,但它之前用于价格比较 } if(!hasUav) { hasUav = true; } } } if(!hasUav) { System.out.println("There is no UAV"); } else { // 在这里,mostExpensive和leastExpensive实际上存储的是索引,但它们在循环中被当作价格来比较 System.out.println("nInformation about the most expensive UAV: n" + flyingObjects[mostExpensive] + "n"); System.out.println("Information about the least expensive UAV: n" + flyingObjects[leastExpensive]); } }
上述代码的主要问题在于:
立即学习“Java免费学习笔记(深入)”;
- 变量混淆: mostExpensive 和 leastExpensive 变量被尝试同时用于存储价格(在比较时)和索引(在赋值时)。它们的初始值 -1 和 1000000000 试图作为价格的边界,但随后又被赋予了数组索引 i。
- 类型不匹配的比较: a.getPrice() 返回 double 类型,而 mostExpensive 和 leastExpensive 是 int 类型。虽然Java会自动进行类型转换,但逻辑上将一个价格与一个索引进行比较是错误的。
- 初始化问题: 即使变量类型正确,mostExpensive 初始化为 0d 或 Double.MIN_VALUE,leastExpensive 初始化为 Double.MAX_VALUE 才是正确的起始点。
3. 正确的实现方法
为了正确地找到最昂贵和最便宜的 UAV,我们需要分离价格和索引的跟踪变量,并确保它们被正确初始化和更新。
3.1 核心思路
- 独立变量: 使用单独的变量来存储当前找到的最高/最低价格,以及这些价格对应的对象在数组中的索引。
- 正确初始化:
- 最高价格初始化为一个足够小的值(例如 0.0 或 Double.MIN_VALUE)。
- 最低价格初始化为一个足够大的值(例如 Double.MAX_VALUE)。
- 索引变量可以初始化为 -1,表示尚未找到任何匹配对象。
- 遍历与类型检查: 遍历数组,使用 instanceof 运算符检查当前对象是否是 UAV 类型。
- 价格与索引更新: 如果当前对象是 UAV,获取其价格,并与当前最高/最低价格进行比较。如果发现新的最高/最低价格,则同时更新价格变量和对应的索引变量。
- 处理无匹配项: 在循环结束后,检查是否找到了任何 UAV 对象(例如,通过检查索引变量是否仍为初始值 -1 或使用一个布尔标志)。
3.2 示例代码
import java.util.Objects; // For Objects.toString() if needed for better output // 假设 FlyingObjects, Uav, AgriculturalDrone, Mav, Multirotor, Helicopter, airplane 类已定义 // 且 Uav 类具有 getPrice() 方法 class FlyingObjects { protected double price; public FlyingObjects(double price) { this.price = price; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "FlyingObject [price=" + price + "]"; } } class Uav extends FlyingObjects { private int someOtherProp; // Example property public Uav(double price, int someOtherProp) { super(price); this.someOtherProp = someOtherProp; } @Override public String toString() { return "UAV [price=" + price + ", someOtherProp=" + someOtherProp + "]"; } } class AgriculturalDrone extends Uav { private String model; private double payloadCapacity; public AgriculturalDrone(double price, int someOtherProp, String model, double payloadCapacity) { super(price, someOtherProp); this.model = model; this.payloadCapacity = payloadCapacity; } @Override public String toString() { return "AgriculturalDrone [price=" + price + ", model=" + model + ", payloadCapacity=" + payloadCapacity + "]"; } } class Mav extends Uav { private String name; private int range; public Mav(double price, int someOtherProp, String name, int range) { super(price, someOtherProp); this.name = name; this.range = range; } @Override public String toString() { return "MAV [price=" + price + ", name=" + name + ", range=" + range + "]"; } } // 示例中未提供的其他类,为完整性假设它们存在并继承自FlyingObjects class Airplane extends FlyingObjects { private int maxSpeed; public Airplane(String model, double price, int maxSpeed) { super(price); this.maxSpeed = maxSpeed; } @Override public String toString() { return "Airplane [price=" + price + ", maxSpeed=" + maxSpeed + "]"; } } class Helicopter extends Airplane { // Assuming Helicopter extends Airplane based on original tree private int rotorBlades; public Helicopter(String model, double price, int maxSpeed, int rotorBlades, int year, int month) { super(model, price, maxSpeed); this.rotorBlades = rotorBlades; } @Override public String toString() { return "Helicopter [price=" + price + ", rotorBlades=" + rotorBlades + "]"; } } class Multirotor extends Helicopter { private int motors; public Multirotor(String model, double price, int maxSpeed, int rotorBlades, int year, int month, int motors) { super(model, price, maxSpeed, rotorBlades, year, month); this.motors = motors; } @Override public String toString() { return "Multirotor [price=" + price + ", motors=" + motors + "]"; } } public class FlyingObjectAnalyzer { public static void findLeastAndMostExpensiveUAV(FlyingObjects[] flyingObjects) { // 独立跟踪最高/最低价格和对应的索引 double maxPrice = 0.0; // 初始最高价格可以设为0或Double.MIN_VALUE int maxPricedUavIndex = -1; // 初始索引设为-1,表示未找到 double minPrice = Double.MAX_VALUE; // 初始最低价格设为Double.MAX_VALUE int minPricedUavIndex = -1; // 初始索引设为-1,表示未找到 // 检查数组是否为空或null if (flyingObjects == null || flyingObjects.length == 0) { System.out.println("The array is empty or null. No UAVs to analyze."); return; } for (int i = 0; i < flyingObjects.length; i++) { // 检查当前对象是否是UAV或其子类 if (flyingObjects[i] instanceof Uav) { Uav currentUav = (Uav) flyingObjects[i]; // 安全向下转型 double currentPrice = currentUav.getPrice(); // 更新最高价格和对应的索引 if (currentPrice > maxPrice) { maxPrice = currentPrice; maxPricedUavIndex = i; } // 更新最低价格和对应的索引 if (currentPrice < minPrice) { minPrice = currentPrice; minPricedUavIndex = i; } } } // 输出结果 if (maxPricedUavIndex != -1) { // 如果找到了UAV System.out.println("nInformation about the most expensive UAV: "); System.out.println(flyingObjects[maxPricedUavIndex]); System.out.println("Price: " + maxPrice); System.out.println("nInformation about the least expensive UAV: "); System.out.println(flyingObjects[minPricedUavIndex]); System.out.println("Price: " + minPrice); } else { System.out.println("No UAVs found in the array."); } } public static void main(String[] args) { FlyingObjects[] test = new FlyingObjects[7]; test[0] = new Uav(10, 43); test[1] = new AgriculturalDrone(8000, 780000, "Chase", 2400); test[2] = new Uav(10, 5); // Price 10 test[3] = new Mav(0.5, 140000, "trooper", 10); // Price 0.5 test[4] = new Multirotor("Hexa", 140000, 200, 185, 2021, 1, 4); // Not a UAV test[5] = new Helicopter("Robinson", 199000, 250, 100, 2018, 7); // Not a UAV test[6] = new Airplane("Boeing", 350000, 450); // Not a UAV findLeastAndMostExpensiveUAV(test); System.out.println("n--- Testing with no UAVs ---"); FlyingObjects[] noUavs = new FlyingObjects[2]; noUavs[0] = new Airplane("Small Plane", 100000, 300); noUavs[1] = new Helicopter("MiniCopter", 50000, 150, 4, 2020, 5); findLeastAndMostExpensiveUAV(noUavs); System.out.println("n--- Testing with empty array ---"); FlyingObjects[] emptyArray = new FlyingObjects[0]; findLeastAndMostExpensiveUAV(emptyArray); System.out.println("n--- Testing with null array ---"); FlyingObjects[] nullArray = null; findLeastAndMostExpensiveUAV(nullArray); } }
3.3 注意事项与总结
- 变量语义清晰: 始终确保变量的命名和用途保持一致。maxPrice 存储价格,maxPricedUavIndex 存储索引,避免混淆。
- 正确初始化边界值:
- 查找最小值时,初始值应设置为可能的最大值 (Double.MAX_VALUE),以便任何实际值都能成为第一个最小值。
- 查找最大值时,初始值应设置为可能的最小值 (0.0 或 Double.MIN_VALUE),以便任何实际值都能成为第一个最大值。
- 索引初始化为 -1 是一个好的实践,它表示“未找到”,因为有效的数组索引总是非负的。
- 类型检查与向下转型: 使用 instanceof 运算符进行类型检查是安全的,确保在向下转型 ((Uav) flyingObjects[i]) 之前对象确实是目标类型或其子类,避免 ClassCastException。
- 处理空数组或无匹配项: 在遍历之前检查数组是否为 null 或空,并在循环结束后检查是否实际找到了匹配的对象(通过检查索引是否仍为初始的 -1),这增强了代码的健壮性。
- 继承层级: instanceof 运算符会检查对象是否是指定类的实例,或者指定类的子类的实例。这意味着如果 AgriculturalDrone 和 Mav 继承自 Uav,那么 instanceof Uav 也会对它们返回 true,这是符合预期的行为。
通过遵循这些原则,可以有效地在复杂对象数组中定位和分析特定类型的元素,确保程序的正确性和健壮性。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END