简体   繁体   English

在Java中,如果子类具有不同的类型,我可以以某种方式将字段移至超类吗?

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

In my Java program, I have two classes that are really similar, and it would make a lot of sense to create a superclass for them to subclass and generalize a bunch of their methods. 在我的Java程序中,我有两个真正相似的类,因此为它们创建一个超类以将其子类化并推广一堆方法将非常有意义。

The only problem is that one of their key fields is implemented in one as a Queue and in one as a PriorityQueue . 唯一的问题是,它们的关键字段之一是作为Queue实现的,而一个字段是PriorityQueue

Is there any way to superclass these and somehow generalize the field type and let the subclasses pick what it will perhaps on instantiation? 有什么方法可以超类化这些类并以某种方式泛化字段类型,并让子类选择在实例化时可能会做什么?

public Base{

}

public Sub1{
     Queue<Customer> customers;
}

public Sub2{
     PriorityQueue<Customer> customers;
}

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

What you need to do is have the queue of customers as a dependency in Base and let the client code decide what queue to instantiate. 你需要做的是有排队customers作为一个依赖Base ,让客户端代码决定什么排队实例。

public Base{
  private Queue<Customer> customers;

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

}

You don't need the Sub1 and Sub2 classes since they only differ from Base in terms of the queue used. 您不需要Sub1Sub2类,因为它们仅在使用的队列方面不同于Base Client code can simply decide what queue to use : 客户代码可以简单地决定使用哪个队列:

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

The PriorityQueue class implements the Queue interface, so I'd recommend making Base an abstract class and keep the customers collection (of type Queue ) in there. PriorityQueue类实现了Queue接口,所以我建议将Base作为抽象类,并在其中保留customers集合( Queue类型)。 Then instantiate customers from Sub1 or Sub2 's constructor as appropriate. 然后根据需要从Sub1Sub2的构造函数实例化customers

Yes, since PriorityQueue implements Queue . 是的,因为PriorityQueue实现了Queue If you want to delegate creation to subclasses, have them pass the appropriate Queue to use to the base constructor: 如果要将创建委托给子类,请让它们将适当的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>());
     }
}

I should mention that if Sub2 needs to use methods that are specific to PriorityQueue (such as comparator ) in some Sub2 -specific method, it can either: 我应该提到,如果Sub2需要在某些特定于Sub2方法中使用特定于PriorityQueue (例如comparator ),则可以:

  1. Cast customers (since it knows that customers is actually a PriorityQueue<Customer> , not just a Queue<Customer> ), or 强制转换customers (因为它知道customers实际上是PriorityQueue<Customer> ,而不仅仅是Queue<Customer> ),或者

  2. Declare its own instance field which will keep the typed reference: 声明自己的实例字段,该实例字段将保留键入的引用:

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

#2 keeps the casting required to a minimum and nicely contained to just the constructor, making it easier to change PriorityQueue<Customer> to something else later. #2使所需的转换保持在最低限度,并且仅包含在构造函数中,可以轻松地将PriorityQueue<Customer>更改为其他内容。

Yes, if you implement the field as Queue , you can instantiate the field as a PriorityQueue in Sub2 , because PriorityQueue implements Queue (source: http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html ) 是的,如果将字段实现为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>());
    }
}

However, when you need to use the customers field as a PriorityQueue (rather than a Queue ) inside Sub2 , you will need to cast it to a PriorityQueue . 但是,当您需要将customers字段用作Sub2内的PriorityQueue (而不是Queue )时,需要将其Sub2转换为PriorityQueue

One solution is to give your customers attribute the general Queue type, which will give you flexibility. 一种解决方案是为customers属性提供常规的Queue类型,这将为您提供灵活性。 But if you want to enforce specific implementations in a given subclass, and carry that information in the rest of your program, you can use generic constraints : 但是,如果您想在给定的子类中实施特定的实现,并在程序的其余部分中携带该信息,则可以使用通用约束:

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>());
   }
}

This can be useful, as it allows you to call, say, customers.comparator() inside Sub2 without having to cast customers into a PriorityQueue . 这很有用,因为它允许您在Sub2内部调用,例如, customers.comparator() ,而无需将customers转换为PriorityQueue

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM