Java中从列表路由方法调用的最佳方法

Java中从列表路由方法调用的最佳方法,java,polymorphism,overloading,instanceof,visitor-pattern,Java,Polymorphism,Overloading,Instanceof,Visitor Pattern,根据列表中不同的对象类型调用类的不同方法的最佳方法是什么 常见示例: 公共类狗扩展动物{ ... 公开声明{ 我是一只狗; } 公营猫科动物{ ... 公开声明{ 系统输出(“我是一只猫”); } 公共类其他类{ 公共空位路线(){ 列表列表=新的ArrayList(); a、 添加(新狗()); a、 添加(新的Cat()); 对于动物(a:aList) methodOverloaded(a);-->这就是你需要在Animal中定义方法并使其抽象化的要点 abstract class Anim

根据列表中不同的对象类型调用类的不同方法的最佳方法是什么

常见示例:

公共类狗扩展动物{
...
公开声明{
我是一只狗;
}
公营猫科动物{
...
公开声明{
系统输出(“我是一只猫”);
}
公共类其他类{
公共空位路线(){
列表列表=新的ArrayList();
a、 添加(新狗());
a、 添加(新的Cat());
对于动物(a:aList)

methodOverloaded(a);-->这就是你需要在Animal中定义方法并使其抽象化的要点

abstract class Animal {
    public abstract void say();
}
这样,你就可以在动物的每个孩子身上覆盖这个方法,你所要做的就是
a.say()

每个对象将调用各自的方法。

最好的方法是在Animal中定义抽象方法并在子类中重写它。这就是多态性的工作原理

不需要过载

public abstract class Animal {
    public abstract void say();
}

public class Dog extends Animal {

    @Override
    public void say() {
        System.out.println("Bark");
    }
}

public class Cat extends Animal {

    @Override
    public void say() {
        System.out.println("Meow");
    }
}
用法

public class Main() {
    public static void main(String[] args) {
        List<Animals> aList = new ArrayList<>();
        a.add(new Dog());
        a.add(new Cat());
        for (Animals a : aList)
            a.say();
    }
}
Bark
Meow
\uuuuuuuu更新\uu 1

我想补充一些意见,为什么重载这些方法不是一个好主意

如果将以下内容添加到代码中,它将编译:

public methodOverloaded(Animal a) {
    a.say();
}
但是它不会像您期望的那样工作。它将调用
public method重载(Animal a)
来获取
列表的所有元素

为什么会发生这种情况

对于循环的所有迭代,参数的编译时类型为
Animal
。每次迭代的运行时类型不同,但这并不影响重载的选择。因为参数的编译时类型为
Animal
,所以唯一适用的重载是第三个重载

此程序的行为违反直觉,因为重载方法之间的选择是静态的,而重写方法之间的选择是动态的。

根据调用方法的对象的运行时类型,在运行时选择重写方法的正确版本

这可以通过以下方式解决:

public methodOverloaded(Animal a) {
    if (a instanceof Cat) ? "Meow" : 
       (a instanceof Dog) ? "Bark" : "Unknown Animal"
}
当然,带有重写方法的建议选项演示了更好的方法和更干净的代码

此外,一项安全、保守的政策是永远不要将两个过载与 相同数量的参数,因为这可能会混淆API的客户端。您可以始终为方法指定不同的名称,而不是重载它们

但有一种情况是,每对重载中至少有一个对应的形式参数在两个重载中具有“完全不同”的类型(显然不可能将任何一种类型的实例强制转换为另一种类型)


例如,
ArrayList
有一个构造函数接受
int
,第二个构造函数接受
集合。很难想象在任何情况下调用这两个构造函数中的哪一个会有任何混淆。

您可以这样做:

for(Animals a:aList){
    if(a instanceof Dog){
        methodOverloaded((Dog) a);
    }else if(a instanceof Cat){
        methodOverloaded((Cat) a);
    }
}
但是根据您在问题中描述的场景,@J-Alex answer是一个很好的方法。

我可以向您展示“工厂设计模式”是如何适合这里的。 定义主类,如下所示:

public abstract class Animal {
    public abstract void say();
}


public class Dog extends Animal {

    @Override
    public void say() {
        System.out.println("Bark");
    }
}
public class Cat extends Animal {

    @Override
    public void say() {
        System.out.println("Meow");
    }
}

public class FactoryClass{

public static Animal getCorrectAnimal(String type){
 if("Cat".equalsIgnoreCase(type)) return new Cat();
 else if ("Dog".equalsIgnoreCase(type)) return new Dog();

return null;
}

}


public class TestFactoryClass {

    public static void main(String[] args) {
        Animal an = ComputerFactory.getCorrectAnimal("Cat");
        List<Animals> aList = new ArrayList<>();
        a.add(FactoryClass.getCorrectAnimal("Dog"));
        a.add(FactoryClass.getCorrectAnimal("Cat"));
        for (Animals a : aList)
            a.say();
    }

    }

}
公共抽象类动物{
公开摘要无效说();
}
公家犬{
@凌驾
公开声明{
System.out.println(“树皮”);
}
}
公营猫科动物{
@凌驾
公开声明{
System.out.println(“喵喵”);
}
}
公共类FactoryClass{
公共静态动物(字符串类型){
如果(“Cat”.equalsIgnoreCase(type))返回新的Cat();
else if(“Dog.equalsIgnoreCase(type))返回新的Dog();
返回null;
}
}
公共类TestFactoryClass{
公共静态void main(字符串[]args){
动物an=计算机工厂.getCorrectAnimal(“猫”);
列表列表=新的ArrayList();
a、 添加(FactoryClass.getCorrectAnimal(“狗”);
a、 添加(FactoryClass.getCorrectAnimal(“Cat”);
对于动物(a:aList)
a、 say();
}
}
}

相信我,如果你在这里分析抽象级别,那就太棒了。客户/消费者不必知道狗或猫类,他/她只需要知道类型和一般抽象类动物。如果你使用更高级别的抽象,你甚至可以在这里去掉类型;你可以阅读“抽象工厂设计”通过这种方式,您公开了最少的类特性(例如,在这里,您通过直接将Dog和Cat类与新的In main类一起使用,公开了它们)。如果您满意,请向上投票。

好的,但如果我非常想调用example的其他类的重载方法,该怎么办?您可以这样做,但这不是设计类的好方法。您的两个方法都可以组合在一个中,因为它们在同一个abstr操作上具有共享逻辑。依赖项反转原则鼓励使用abstr操作。如果您有其他目标,请描述它,我会尽力帮助您。在您的示例中,重载这两种方法是没有意义的。您的需求的最佳实践是使用java中的factory design模式。@tommasoballardini请阅读factory design模式,您会得到答案。请阅读我更新的答案,可能是m现在很清楚了,非常感谢much@tommasoballardini这里也不需要强制转换或直接使用类。
Factory
是创造性的设计模式,这里的“路由”机制仍然是多态性。你做了同样的事情,但使用了另一种对象创建方法。
Factory
如果你有一个public const构造函数。不要混淆应用程序不同组件的责任。@J-Alex这就是为什么它是最好的方法之一。请尝试理解tommasoballardini提出的问题。您不同意它是更好的方法吗?
public abstract class Animal {
    public abstract void say();
}


public class Dog extends Animal {

    @Override
    public void say() {
        System.out.println("Bark");
    }
}
public class Cat extends Animal {

    @Override
    public void say() {
        System.out.println("Meow");
    }
}

public class FactoryClass{

public static Animal getCorrectAnimal(String type){
 if("Cat".equalsIgnoreCase(type)) return new Cat();
 else if ("Dog".equalsIgnoreCase(type)) return new Dog();

return null;
}

}


public class TestFactoryClass {

    public static void main(String[] args) {
        Animal an = ComputerFactory.getCorrectAnimal("Cat");
        List<Animals> aList = new ArrayList<>();
        a.add(FactoryClass.getCorrectAnimal("Dog"));
        a.add(FactoryClass.getCorrectAnimal("Cat"));
        for (Animals a : aList)
            a.say();
    }

    }

}