【问题标题】:Overloading Java function with List<> parameter使用 List<> 参数重载 Java 函数
【发布时间】:2011-01-15 12:55:29
【问题描述】:

我有两节课

public class Customer{
  ...
  public String getCustomerNumber();
  ...
}

public class Applicant{
   ....
   private Customer c;
   public Customer getCustomer(){ return c; }
   ...
}

当出现客户或申请人列表时,我想要一个函数来迭代列表并使用 CustomerNumber 执行某些操作。

我试过重载函数

public void processCustomerNumbers(List<Customer> custList)
...

public void processCustomerNumbers(List<Applicant> appList)
...

但是这些被视为重复的方法...有没有一种很好的方法来做到这一点,而不是仅仅拥有 2 个不同命名的函数?

【问题讨论】:

    标签: java list function arguments


    【解决方案1】:

    改用数组。

    public void processCustomerNumbers(Customer[] custList)
    ...
    
    public void processCustomerNumbers(Applicant[] appList)
    ...
    

    当您尝试使用列表调用这些方法时,将列表转换为数组:

    List<Customer> customers;
    List<Applicant> applicants;
    ...
    processCustomerNumbers(customers.toArray(new Customer[]{});
    processCustomerNumbers(applicants.toArray(new Applicant[]{});
    

    【讨论】:

      【解决方案2】:

      解决此问题的一种方法是定义自定义列表类型,如下所示:

      class CustomerList extends ArrayList<Customer> {
          ...
      }
      
      class ApplicantList extends ArrayList<Applicant> {
          ...
      }
      

      那么下面的重载是合法的:

      public void processCustomerNumbers(CustomerList custList)
      
      public void processCustomerNumbers(ApplicantList appList)
      

      但是,我认为这不是一个好主意。首先,它将特定的实现类硬连线到应用程序的 API 中。

      更好的方法是为客户和申请人定义一个通用接口,允许您使用一个processCustomerNumbers 方法处理它们。 (如其他答案中详细描述的那样。)

      【讨论】:

        【解决方案3】:

        在进入方法名称之前,类层次结构有点混乱......

        public class Customer{          
          ...          
          public String getCustomerNumber();          
          ...          
        }          
        
        public class Applicant{          
           ....          
           private Customer c;          
           public Customer getCustomer(){ return c; }          
           ...          
        }    
        

        为什么申请人和客户应该是 不同的对象?你能告诉 这些对象之间的关系?

        【讨论】:

          【解决方案4】:

          如果你让两个类都实现一个通用接口,

          interface CustomerNumber {
              String getCustomerNumber();
          }
          
          public class Customer implements CustomerNumber {
            ...
            public String getCustomerNumber();
            ...
          }
          
          public class Applicant implements CustomerNumber {
             ....
             private Customer c;
             public Customer getCustomer() { return c; }
             public String getCustomerNumber() { return getCustomer().getCustomerNumber(); }
             ...
          }
          

          那么你也许可以用一个方法做你想做的事:

          public void processCustomerNumbers(List<? extends CustomerNumber> appList) {
              for (Customer c: appList) {
                  processCustomerNumber(c.getCustomerNumber());
              }
          }
          

          【讨论】:

            【解决方案5】:

            泛型具有所谓的类型擦除 - List&lt;Customer&gt;List&lt;Applicant&gt; 是同一类型,编译器只是对您可以使用它们执行的操作设置了编译时限制。

            您可以检查列表中第一个对象的类型,并在此基础上调用(不同名称的)内部方法。

            【讨论】:

            • 是的,那是我开始研究的东西,检查课程并改变行为。来到 SO 希望有一个更优雅的解决方案,如果没有任何问题,我会继续沿着这条路走。
            • 作为其他问题,覆盖选择是在编译时完成的,因此擦除不排除它。
            • 在我看来,这种代码可以归类为“意大利面条代码”。我更喜欢stackoverflow.com/a/2241584/4149078,因为强制你实现面向对象的代码。
            【解决方案6】:

            Java 中泛型的问题是泛型类型在运行时被删除,因此这两种方法都编译为相同的签名。您将需要有单独的方法名称,或在运行时检查列表元素的类型。

            【讨论】:

            • Java 并不总是有泛型;添加它们时,生成的字节码没有改变。
            • 是的,这就是使用类型擦除的原因——以避免破坏与前泛型代码的向后兼容性。
            • 该类型在运行时被擦除。方法重载选择在编译时完成。因此,即使有擦除,编译器也有足够的信息来决定。但是,如果发生这种语言更改,则会出现二进制表示和兼容性问题。
            猜你喜欢
            • 1970-01-01
            • 2021-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-16
            • 1970-01-01
            • 2013-03-06
            • 1970-01-01
            相关资源
            最近更新 更多