在 Java 中,如果子类具有不同的类型,我能否以某种方式将字段移动到超类?

In Java, can I somehow move field to superclass if subclasses have different types for them?

在我的 Java 程序中,我有两个非常相似的 类 ,为它们创建一个超类来继承和概括它们的一堆方法很有意义.

唯一的问题是他们的一个关键字段在一个 Queue 和另一个 PriorityQueue 中实现。

是否有任何方法可以对这些进行超类化并以某种方式概括字段类型并让子类选择它可能在实例化时使用的内容?

public Base{

}

public Sub1{
     Queue<Customer> customers;
}

public Sub2{
     PriorityQueue<Customer> customers;
}

priorityqueue 是实现队列的抽象队列的子类,所以基本上 base 可以有一个客户队列。

您需要做的是将 customers 的队列作为 Base 中的依赖项,让客户端代码决定实例化哪个队列。

public Base{
  private Queue<Customer> customers;

  protected Base(Queue<Customer> customers) {
     this.queue = queue;
  }

}

您不需要 Sub1Sub2 类,因为它们仅在使用的队列方面与 Base 不同。客户端代码可以简单地决定使用什么队列:

Base baseWithQueue = new Base(new ArrayBlockingQueue<Customer>());
Base baseWithPriorityQueue = new Base(new PriorirityQueue<Customer>());

PriorityQueue class 实现了 Queue 接口,所以我建议将 Base 抽象为 class 并保留 customers 集合(Queue 类型)。然后从 Sub1Sub2 的构造函数中根据需要实例化 customers

是的,因为 PriorityQueue implements Queue。如果您想将创建委托给子类,请让它们传递适当的 Queue 以用于基本构造函数:

public class Base {
    protected final Queue<Customer> customers;

    protected Base(Queue<Customer> c) {
        this.customers = c;
    }
}

public class Sub1 extends Base {
     Sub1() {
        super(new WhateverQueue<Customer>());
     }
}

public class Sub2 extends Base {
     Sub2() {
         super(new PriorityQueue<Customer>());
     }
}

我应该提一下,如果Sub2需要在某些Sub2特定的方法中使用特定于PriorityQueue的方法(例如comparator),它可以或者:

  1. Cast customers(因为它知道customers实际上是一个PriorityQueue<Customer>,而不仅仅是一个Queue<Customer>),或者

  2. 声明它自己的实例字段,它将保留类型化引用:

    private PriorityQueue<Customer> priorityCustomers;
    
    Sub2() {
        super(new PriorityQueue<Customer>());
        this.priorityCustomers = (PriorityQueue<Customer>)(this.customers);
    }
    

#2 将所需的转换保持在最低限度,并且很好地包含在构造函数中,这样以后更容易将 PriorityQueue<Customer> 更改为其他内容。

是的,如果将字段实现为Queue,则可以将字段实例化为Sub2中的PriorityQueue,因为PriorityQueue实现了Queue (来源:http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html

public Base{
     Queue<Customer> customers;
     public Base(Queue<Customers> queue){
         this.customers = queue;
     }
}

public Sub1{
    public Sub1(){
        super(new Queue<Customer>());
    }
}

public Sub2{
     public Sub2(){
        super(new PriorityQueue<Customer>());
    }
}

但是,当您需要在 Sub2 中将 customers 字段用作 PriorityQueue(而不是 Queue)时,您需要将其转换为一个 PriorityQueue.

一种解决方案是为您的 customers 属性提供通用 Queue 类型,这将为您提供灵活性。但是如果你想在给定的子类中强制执行特定的实现,并在你的程序的其余部分携带该信息,你可以使用通用约束:

public class Base<Q extends Queue<Customers>> {
    protected Q customers;

    public Base(Q customers) {
        this.customers = customers;
    }
}

public Sub1 extends Base<Queue<Customers>> {
   public Sub1(Queue<String> customers) {
      super(customers);
   }
}

public Sub2 extends Base<PriorityQueue<Customers>>{
   public Sub2() {
       // Sub2 only supports PriorityQueues
      super(new PriorityQueue<String>());
   }
}

这很有用,因为它允许您在 Sub2 中调用 customers.comparator() 而无需将 customers 转换为 PriorityQueue.