将子类传递给方法,但将超类作为参数?

40

我有一个抽象类Vehicle,它有两个实现的子类RedVehicleYellowVehicle.

另一个类中有一个List<Vehicle>,其中包含两个子类的实例。

我想能够传入一个类类型并使用该类型来决定在List中要对哪组对象进行某些操作。

由于Class是通用的,所以我应该将其参数化为某些内容,但是将参数放置为父类Vehicle会导致调用代码无法工作,因为exampleMethod现在期望的是Vehicle类型,而不是RedVehicleYellowVehicle的子类。

我感觉应该有一种简洁的方法来解决这个问题,那么实现此功能的正确方法是什么呢?

n.b. 我不一定要传递Class类型,如果有更好的建议,我很乐意尝试。

调用代码:

service.exampleMethod(RedVehicle.class);
service.exampleMethod(YellowVehicle.class);

字段/方法:

//List of vehicles
//Vehicle has 2 subclasses, RedVehicle and YellowVehicle
private List<Vehicle> vehicles;

//Having <Vehicle> as the Class parameter stops the calling code working
public void exampleMethod(Class<Vehicle> type) 
{
    for(Vehicle v : vehicles)
    {
        if(v.getClass().equals(type))
        {
            //do something
        }
    }
}
4个回答

76
请改为以下操作:
public <T extends Vehicle> void exampleMethod(Class<T> type) 

我知道这一定是某些简单的东西。在返回类型之前使用通用类型有特殊的名称吗?或者提供一个通用来源链接也可以。我会尝试明天,如果有效就接受,谢谢。 - Peanut
1
请查看Oracle的泛型介绍或Angelika Langer的Java泛型FAQ。对于mprivat的直接解决方案,加1分。 - DaveFar
1
@DaveBall 感谢您提供Angelika Langer的建议,我知道泛型作为一个概念并且已经使用过它们,但从未深入研究过。这似乎是一个非常深入的讨论。对于其他有兴趣的人,这是链接:http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html - Peanut
这个答案的详细说明可以在这里找到。 - Sufian
@Peanut 它们被称为通用方法。 - veritas
我理解了在支持类型Vehicle的参数中的Class<T>部分。现在我明白了,如果一个方法在其参数中使用了泛型<T>,那么它需要在方法语法结构中添加到返回类型之前。 - veritas

3

为什么不使用访问者模式

这样你就可以

  • 不需要类型标记
  • 让动态分派处理情况区分(而不是if(v.getClass().equals(type))
  • 更加灵活(遵循OCP

详细说明:
您的抽象类 Vehicle 获得了一个方法 accept(Visitor v),具体子类通过调用 v 上的适当方法来实现它。
public interface Visitor {
  visitRedVehicle(RedVehicle red);
  visitYellowVehicle(YellowVehicle yellow);
}

使用访问者:
public class Example {

  public void useYellowOnly() {
    exampleMethod(new Visitor() {
        visitRedVehicle(RedVehicle red) {};
        visitYellowVehicle(YellowVehicle yellow) {
             //...action
        });
  }
  public void exampleMethod(Visitor visitor){
      for(Vehicle v : vehicles) {
          v.accept(visitor);
      }  
  }
}

1
我发现这个语法按预期工作:
public void exampleMethod(Class<? extends Vehicle> type) 

0

接受的答案有效并帮助我达到了目标。我想补充一下,以便更清楚地向任何可能需要它的人解释。

在这种情况下,RevisedExposure是Exposure的子类。我需要使用这两个类之一的列表调用GetMetadata(),这将导致相同的结果集。

private async Task<List<Metadata>> GetMetadata<T>(List<T> exposures) where T : Exposure

现在我可以从两个不同的地方调用这个方法,使用不同版本的列表,就像这样。
var metadata = await GetExposureMetadata(revisions);

或者

var metadata = await GetExposureMetadata(exposures);

非常好用!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接