如何在Java数组中查找最昂贵和最便宜的对象

如何在Java数组中查找最昂贵和最便宜的对象

本文详细介绍了在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免费学习笔记(深入)”;

  1. 变量混淆: mostExpensive 和 leastExpensive 变量被尝试同时用于存储价格(在比较时)和索引(在赋值时)。它们的初始值 -1 和 1000000000 试图作为价格的边界,但随后又被赋予了数组索引 i。
  2. 类型不匹配的比较: a.getPrice() 返回 double 类型,而 mostExpensive 和 leastExpensive 是 int 类型。虽然Java会自动进行类型转换,但逻辑上将一个价格与一个索引进行比较是错误的。
  3. 初始化问题: 即使变量类型正确,mostExpensive 初始化为 0d 或 Double.MIN_VALUE,leastExpensive 初始化为 Double.MAX_VALUE 才是正确的起始点。

3. 正确的实现方法

为了正确地找到最昂贵和最便宜的 UAV,我们需要分离价格和索引的跟踪变量,并确保它们被正确初始化和更新。

3.1 核心思路

  1. 独立变量: 使用单独的变量来存储当前找到的最高/最低价格,以及这些价格对应的对象在数组中的索引。
  2. 正确初始化:
    • 最高价格初始化为一个足够小的值(例如 0.0 或 Double.MIN_VALUE)。
    • 最低价格初始化为一个足够大的值(例如 Double.MAX_VALUE)。
    • 索引变量可以初始化为 -1,表示尚未找到任何匹配对象。
  3. 遍历与类型检查: 遍历数组,使用 instanceof 运算符检查当前对象是否是 UAV 类型。
  4. 价格与索引更新: 如果当前对象是 UAV,获取其价格,并与当前最高/最低价格进行比较。如果发现新的最高/最低价格,则同时更新价格变量和对应的索引变量。
  5. 处理无匹配项: 在循环结束后,检查是否找到了任何 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 注意事项与总结

  1. 变量语义清晰: 始终确保变量的命名和用途保持一致。maxPrice 存储价格,maxPricedUavIndex 存储索引,避免混淆。
  2. 正确初始化边界值:
    • 查找最小值时,初始值应设置为可能的最大值 (Double.MAX_VALUE),以便任何实际值都能成为第一个最小值。
    • 查找最大值时,初始值应设置为可能的最小值 (0.0 或 Double.MIN_VALUE),以便任何实际值都能成为第一个最大值。
    • 索引初始化为 -1 是一个好的实践,它表示“未找到”,因为有效的数组索引总是非负的。
  3. 类型检查与向下转型: 使用 instanceof 运算符进行类型检查是安全的,确保在向下转型 ((Uav) flyingObjects[i]) 之前对象确实是目标类型或其子类,避免 ClassCastException。
  4. 处理空数组或无匹配项: 在遍历之前检查数组是否为 null 或空,并在循环结束后检查是否实际找到了匹配的对象(通过检查索引是否仍为初始的 -1),这增强了代码的健壮性。
  5. 继承层级: instanceof 运算符会检查对象是否是指定类的实例,或者指定类的子类的实例。这意味着如果 AgriculturalDrone 和 Mav 继承自 Uav,那么 instanceof Uav 也会对它们返回 true,这是符合预期的行为。

通过遵循这些原则,可以有效地在复杂对象数组中定位和分析特定类型的元素,确保程序的正确性和健壮性。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享