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



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

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()方法并改为调用通用打印方法。

我试图避免重复代码,但受到编写不佳的遗留 API 的限制。

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

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为 null,则不要进行服务调用。

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

我在完全掌握这个问题时遇到了一点麻烦。将对象类型作为参数传递到 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.");
    }
}

这看起来像是另一个访问者模式有用的示例。我假设你所有的类都有一些共同的超类型,或者至少你可以很容易地添加一个。因此,代码可能如下所示:

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

产生输出

动物

蔬菜

矿物

最新更新