如何将派生类传递给接受父类型的函数?

5

我有一个名为Sport的基类,其中包含一些变量。我还有一些派生自Sport的不同类,如Volleyball、Soccer等,它们具有额外的方法和变量。它们看起来有点像这样。

public class Sport {
    public String commonVar;
    public Sport(String c) {
        this.commonVar = c;
    }
}

然后是排球:

public class Volleyball extends Sport {
    public String onlyVolleyball;
    public Volleyball(String c, String thisVar) {
        super(c);
        this.onlyVolleyball = thisVar;
    }
}

现在我想把派生自Sport的类传递到其他地方的一个函数中,但是要使参数...
public otherFunction(int one, int two, Sport sport) { }

只将运动视为Sport对象(它会接受派生类,但我无法访问任何不通用于Sport的变量和方法)。我的问题是如何创建一个函数,能够发送所有类型的Sport衍生物而不丢失任何数据?

5个回答

5
你不能直接这样做,但可以检查对象是否属于扩展类的成员,然后对其进行强制类型转换并使用,具体操作如下所示:

public otherFunction(int one, int two, Sport sport)
{
    if(sport instanceof Volleyball)
    {
        Volleyball volley = (Volleyball) sport;
        //Do Volleyball things
    }
    else
    {
        //Only do sport things.
    }
}

我认为这可能是我正在寻找的,有没有更自动化地进行转换的方法?我可以在Sport中设置一个变量 public Class<? extends Sport> c; 并在构造函数中从派生类中设置c。 - Ahorner
1
@Ahorner 不完全是这样,除了在具有扩展类型参数的类中(例如 ArrayList<String>)之外,您无法进行动态转换,因为泛型声明确保了类型安全。如果您查看其源代码,您会发现 E 用于表示扩展类型,在 elementData() 方法中,该值被强制转换为 (E) elementData[index],但是只有在它们彼此共享所有方法的情况下才适用。(ArrayList 源码:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java) - MrLore

4

不可以这样做。如果该函数需要与Sport对象一起使用,则应在Sport中提供所需的所有信息。否则,您应该为每个函数(或策略/处理程序或类似函数)进行拆分。

这将违反面向对象原则中的开闭原则(SOLID中的O)。

但是,您可以使用instanceof检查,然后进行类型转换:

if (sport instanceof Volleyball) {
  Volleyball v = (Volleyball)sport;
}

1

基本上,解决您的问题取决于您真正想要实现什么。

同时,考虑到您的帖子,在我看来,您正在尝试混合不同的职责,这些职责是:

  1. 处理Sport实例。
  2. 处理Sport实例的衍生品。

可能意味着您的方法根本不需要使用Sport实例。它实际上需要的是访问特定的体育项目。如果我理解有误,请纠正我。

因此,最简单的解决方案是声明类似以下的otherFunction:

public otherFunction(int one, int two, VolleyBall sport)
public otherFunction(int one, int two, Soccer sport)
public otherFunction(int one, int two, BasketBall sport)
public otherFunction(int one, int two, AnyOtherAwsomeSport sport)

这样,你就清楚地告诉了你的功能处理哪种类型的运动,并且你有一个非常清晰易懂且易于维护的界面。


你的假设是正确的。不过我认为在这种情况下,instanceof 可能会有更小的代码占用。 - Ahorner

0
你正在处理“表达问题”;这是一个难题。你可以做的一件事是:
public interface SportFunction {
    void doChessFunction(Chess sport);
    void doVolleyballFunction(Volleyball sport);
}

public abstract class Sport {
    public String commonVar;
    public Sport(String c) {
        this.commonVar = c;
    }
    public abstract void doSportFunction(SportFunction function);
}

public class Volleyball extends Sport {
    public String onlyVolleyball;
    public Volleyball(String c, String thisVar) {
        super(c);
        this.onlyVolleyball = thisVar;
    }

    public void doSportFunction(SportFunction function) {
        function.doVolleyballFunction(this);
    }
}

public class Chess extends Sport {
    public int onlyChess;
    public Chess(String c, int thisVar) {
        super(c);
        this.onlyChess = thisVar;
    }

    public void doSportFunction(SportFunction function) {
        function.doChessFunction(this);
    }
}

然后像这样使用类:

public void otherFunction(int one, int two, Sport sport) {
   sport.doSportFunction(new OtherSportFunction(one, two));
}

public class OtherSportFunction implements SportFunction {
   public OtherSportFunction(int one, int two) { /* do stuff */ }
   public void doChessFunction(Chess sport) { /* do chess stuff */ }
   public void doVolleyballFunction(Volleyball sport) { /* do volleyball stuff */ }
}

0

答案是,你不能这样做。你需要向基类添加成员,可能是抽象方法,例如getTypeOfSport()。


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