可以在编译时不知道类型的情况下使用方法重载吗?

时间:2017-03-17 16:53:26

标签: java polymorphism

如果我们采用一个非常基本的例子:

public static void main(String[] args) {
    animalMineralOrVegetable(new Animal());
    animalMineralOrVegetable(new Mineral());
    animalMineralOrVegetable(new Vegetable());
}

public static void animalMineralOrVegetable(Animal animal) {
    print("Animal");
}

public static void animalMineralOrVegetable(Mineral mineral) {
    print("Mineral");
}

public static void animalMineralOrVegetable(Vegetable vegetable) {
    print("Vegetable");
}

由于在编译时已知所有类型,我们得到预期的结果。

但是,如果我们依赖另一个类的方法(例如,具有Object返回类型),正在使用instanceof并使用我们唯一的选项(反射除外)?

public static void main(String[] args) {
    animalMineralOrVegetable(SomeClass.getSubject()); // object return type
}

如果声明的返回类型与其中一个方法实现不匹配(如上所述),上面显然不会编译。

显然,如果方法只返回每个类型实现的接口,我们将重构为单个animalMineralOrVegetable()方法并调用常见的print方法。

我正在努力避免重复代码,但受到编写糟糕的旧API的限制。

3 个答案:

答案 0 :(得分:1)

你提供了一个非常基本的例子,但我可能会尝试这样做:

public AnimalOrMineralWrapper{
    String message;
    T t;

    public AnimalOrMineralWrapper(T t, String message){
        this.t = t;
        this.message = message;
    }
    public String getMessage(){
        return message;
    }
}

您现在可以使用包装类,如下所示:

public static void main(String[] args){
    Mineral mineral = new Mineral();
    AnimalOrMineralWrapper<Mineral> mineral = new AnimalOrMineralWrapper(mineral, "mineral");
}

public static void animalMineralOrVegetable(AnimalOrMineralWrapper wrapper) {
    print(wrapper.getMessage());
}

如果print是一个API调用,你不能只传递任何东西,你可以添加一个额外的实例变量,或者只是在对象实例化时将message设置为null。然后,如果message为空,则不要进行服务调用。

这是一个潜在的解决方案,但我猜你的实现会更复杂。

答案 1 :(得分:0)

我在完全理解这个问题时遇到了一些麻烦。将对象类型作为参数传递给animalMineralOrVegetable()方法会不会有问题?

据推测,你有某种抽象的父类Animal()Mineral()Vegetable()都延伸,我们称之为Food()

public static void main(String[] args) 
{
    Animal animal = new Food();
    Mineral mineral = new Food();
    Vegetable vegetable = new Food();

    animalMineralOrVegetable(animal, Animal.class);
    animalMineralOrVegetable(mineral , Mineral.class);
    animalMineralOrVegetable(vegetable , Vegetable.class);
}

public static void animalMineralOrVegetable(Food foodObject, Class clazz)
{
    if(clazz == Mineral.class)
    {
        // logic
    {
    else if(clazz == Animal.class)
    {
        // logic
    }
    else if(clazz == Vegetable.class)
    {
        // logic
    }
    else
    {
        throw new Exception("Class not recognized.");
    }
}

编辑:要处理未知类型,请instanceof(如您在问题中提到的那样)。在我看来,这似乎非常简单。几个月后回到代码时很容易理解。

public static void animalMineralOrVegetable(Object foodObject)
{
    if(foodObject instanceof Mineral.class)
    {
        print((Mineral) foodObject.getSubject());
    {
    else if(foodObject instanceof Animal.class)
    {
        print((Animal) foodObject.getSubject());
    }
    else if(foodObject instanceof Vegetable.class)
    {
        print((Vegetable) foodObject.getSubject());
    }
    else
    {
        throw new Exception("Passed object type cannot be determined.");
    }
}

答案 2 :(得分:0)

这看起来像Visitor pattern有用的另一个例子。我假设你的所有类都有一些常见的超类型,或者至少你可以轻松添加一个。所以代码看起来像这样:

interface Visitor
{
    void visitAnimal(Animal animal);

    void visitMineral(Mineral mineral);

    void visitVegetable(Vegetable vegetable);
}

abstract class BaseObject
{
    public abstract void visit(Visitor visitor);
}

class Animal extends BaseObject
{
    public String getUniqueAnimalString()
    {
        return "Animal";
    }

    @Override
    public void visit(Visitor visitor)
    {
        visitor.visitAnimal(this);
    }
}

class Mineral extends BaseObject
{
    public String getUniqueMineralString()
    {
        return "Mineral";
    }

    @Override
    public void visit(Visitor visitor)
    {
        visitor.visitMineral(this);
    }
}

class Vegetable extends BaseObject
{
    public String getUniqueVegetableString()
    {
        return "Vegetable";
    }

    @Override
    public void visit(Visitor visitor)
    {
        visitor.visitVegetable(this);
    }
}

然后你可以像这样使用它:

public static void main(String[] args)
{
    List<BaseObject> objects = new ArrayList<>();
    objects.add(new Animal());
    objects.add(new Vegetable());
    objects.add(new Mineral());

    Visitor visitor = new Visitor()
    {
        @Override
        public void visitAnimal(Animal animal)
        {
            System.out.println(animal.getUniqueAnimalString());
        }

        @Override
        public void visitMineral(Mineral mineral)
        {
            System.out.println(mineral.getUniqueMineralString());
        }

        @Override
        public void visitVegetable(Vegetable vegetable)
        {
            System.out.println(vegetable.getUniqueVegetableString());
        }
    };

    for (BaseObject o : objects)
    {
        o.visit(visitor);
    }

}

产生输出

  

动物

     

蔬菜

     

矿物

相关问题