根据List中不同的对象类型调用类的不同方法的最佳方法是什么?
常见示例:
public class Dog extends Animals{
...
public void say(){
System.out("i'm a dog");
}
public class Cat extends Animals{
...
public void say(){
System.out("i'm a cat");
}
public class OtherClass {
public void route(){
List<Animals> aList = new ArrayList<>();
a.add(new Dog());
a.add(new Cat());
for(Animals a:aList)
methodOverloaded(a); ---> that's the point <---
}
public methodOverloaded(Dog d){
d.say();
}
public methodOverloaded(Cat c){
c.say();
}
}
当然,隐喻目标是在第一次迭代时打印I'm a dog
,在第二次运行I'm a cat
时打印methodOverloaded()
。
我试过
instanceOf()
但我正在寻找更好的解决方案。
编辑:我严格要求调用示例OtherClass
的重载方法。
答案 0 :(得分:2)
最好的方法是在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
<强> ____ UPDATE_1 强>
我想补充一些评论为什么重载这些方法不是一个好主意。
如果要将以下内容添加到代码中 - 它将编译:
public methodOverloaded(Animal a) {
a.say();
}
但它不会像你期望的那样起作用。它会为public methodOverloaded(Animal a)
的所有元素调用List
。
为什么会这样?
对于循环的所有迭代,参数的编译时类型为Animal
。运行时类型在每次迭代中都不同,但这不会影响重载的选择。由于参数的编译时类型为Animal
,因此唯一适用的重载是第三个。
此程序的行为是违反直觉的,因为重载方法中的选择是静态的,而重写方法中的选择是动态的。
根据调用方法的对象的运行时类型,在运行时选择正确版本的重写方法。
这可以通过以下方式解决:
public methodOverloaded(Animal a) {
if (a instanceof Cat) ? "Meow" :
(a instanceof Dog) ? "Bark" : "Unknown Animal"
}
当然,建议使用覆盖方法的选项可以说明更好的方法和更干净的代码。
另外,安全,保守的政策永远不会导出两个超载 相同数量的参数,因为它可能会混淆API的客户端。您始终可以为方法指定不同的名称,而不是重载它们。
但是有一种情况是,每对过载中至少有一个相应的形式参数在两个过载中具有“根本不同”(当显然不可能将任何一种类型的实例转换为另一种类型时)。
例如,ArrayList
有一个构造函数接受int
,第二个构造函数接受Collection
。很难想象在任何情况下都会对这两个构造函数中的哪一个进行混淆。
答案 1 :(得分:0)
您需要在Animal中定义方法并将其设为抽象
abstract class Animal {
public abstract void say();
}
这样,您可以在Animal的每个子项中覆盖此方法,您所要做的就是a.say()
每个对象都会调用各自的方法。
答案 2 :(得分:0)
你可以这样做:
for(Animals a:aList){
if(a instanceof Dog){
methodOverloaded((Dog) a);
}else if(a instanceof Cat){
methodOverloaded((Cat) a);
}
}
但根据你在问题中所描述的情景,@ J-Alex回答是一个很好的方法。
答案 3 :(得分:0)
我可以告诉你“工厂设计模式”是如何适合这里的。 定义你的主要类:
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();
}
}
}
相信我,如果你在这里分析一下抽象的程度,那真是太棒了。 客户/消费者永远不必知道Dog或Cat类,他/她只需要知道类型和一般抽象类Animal。如果你使用更高的类,你甚至可以在这里删除类型抽象程度;你可以阅读“抽象工厂设计”。通过这种方式,您可以暴露出最少的类功能(例如,您可以通过直接使用主类中的new来暴露Dog和Cat类)。如果您满意,请提前投票。