从 Java 中的 List 路由方法调用的最佳方式
Best way to route method calling from List in Java
根据 List 中的不同对象类型调用 class 的不同方法的最佳方法是什么?
常见例子:
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
.
的重载方法
您需要在 Animal 中定义方法并使其抽象化
abstract class Animal {
public abstract void say();
}
这样,你就可以在每个child的Animal中重写这个方法了,你所要做的就是a.say()
每个 object 将调用各自的方法。
最好的方法是在 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();
}
但它不会像您期望的那样工作。它将为 List
.
的所有元素调用 public methodOverloaded(Animal a)
为什么会这样?
对于循环的所有迭代,参数的编译时类型为 Animal
。每次迭代运行时类型不同,但这不影响重载的选择。因为参数的编译时类型是 Animal
,唯一适用的重载是第三个。
这个程序的行为是违反直觉的,因为在重载方法中的选择是静态的,而在重载方法中的选择是动态的。
根据调用该方法的对象的运行时类型,在运行时选择被覆盖方法的正确版本。
这可以通过以下方法解决:
public methodOverloaded(Animal a) {
if (a instanceof Cat) ? "Meow" :
(a instanceof Dog) ? "Bark" : "Unknown Animal"
}
当然,带有覆盖方法的建议选项展示了更好的方法和更简洁的代码。
此外,一个安全、保守的策略是从不导出两个重载
相同数量的参数,因为它可以混淆 API 的客户端。你总是可以给方法不同的名字而不是重载它们。
但也有这样的情况,即每对重载中至少有一个相应的形式参数在两个重载中具有“完全不同”的类型(当显然不可能将任何一种类型的实例转换为另一种时)类型。
例如,ArrayList
有一个采用 int
的构造函数和第二个采用 Collection
的构造函数。很难想象在任何情况下都会调用这两个构造函数中的哪一个。
你可以这样做:
for(Animals a:aList){
if(a instanceof Dog){
methodOverloaded((Dog) a);
}else if(a instanceof Cat){
methodOverloaded((Cat) a);
}
}
但根据你在问题中描述的场景,@J-Alex 的回答是个不错的选择。
我可以在这里向您展示 "Factory Design pattern" 是怎样一种合适的方式。
定义你的 main class 如:
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();
}
}
}
相信我,如果您在这里分析抽象级别,那就太棒了。 client/consumer 永远不必知道狗或猫 class,he/she 只需要知道类型和一般摘要 class 动物。 如果你使用更高层次的抽象,你甚至可以在这里去掉类型;您可以为此阅读 "Abstract Factory Design"。通过这种方式,您暴露了最少的 class 特性(就像这里您暴露了 Dog 和 Cat class 一样,通过在 main class 中直接使用 new 来暴露它们)。如果您满意,请点赞。
根据 List 中的不同对象类型调用 class 的不同方法的最佳方法是什么?
常见例子:
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
.
您需要在 Animal 中定义方法并使其抽象化
abstract class Animal {
public abstract void say();
}
这样,你就可以在每个child的Animal中重写这个方法了,你所要做的就是a.say()
每个 object 将调用各自的方法。
最好的方法是在 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();
}
但它不会像您期望的那样工作。它将为 List
.
public methodOverloaded(Animal a)
为什么会这样?
对于循环的所有迭代,参数的编译时类型为 Animal
。每次迭代运行时类型不同,但这不影响重载的选择。因为参数的编译时类型是 Animal
,唯一适用的重载是第三个。
这个程序的行为是违反直觉的,因为在重载方法中的选择是静态的,而在重载方法中的选择是动态的。
根据调用该方法的对象的运行时类型,在运行时选择被覆盖方法的正确版本。
这可以通过以下方法解决:
public methodOverloaded(Animal a) {
if (a instanceof Cat) ? "Meow" :
(a instanceof Dog) ? "Bark" : "Unknown Animal"
}
当然,带有覆盖方法的建议选项展示了更好的方法和更简洁的代码。
此外,一个安全、保守的策略是从不导出两个重载 相同数量的参数,因为它可以混淆 API 的客户端。你总是可以给方法不同的名字而不是重载它们。
但也有这样的情况,即每对重载中至少有一个相应的形式参数在两个重载中具有“完全不同”的类型(当显然不可能将任何一种类型的实例转换为另一种时)类型。
例如,ArrayList
有一个采用 int
的构造函数和第二个采用 Collection
的构造函数。很难想象在任何情况下都会调用这两个构造函数中的哪一个。
你可以这样做:
for(Animals a:aList){
if(a instanceof Dog){
methodOverloaded((Dog) a);
}else if(a instanceof Cat){
methodOverloaded((Cat) a);
}
}
但根据你在问题中描述的场景,@J-Alex 的回答是个不错的选择。
我可以在这里向您展示 "Factory Design pattern" 是怎样一种合适的方式。 定义你的 main class 如:
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();
}
}
}
相信我,如果您在这里分析抽象级别,那就太棒了。 client/consumer 永远不必知道狗或猫 class,he/she 只需要知道类型和一般摘要 class 动物。 如果你使用更高层次的抽象,你甚至可以在这里去掉类型;您可以为此阅读 "Abstract Factory Design"。通过这种方式,您暴露了最少的 class 特性(就像这里您暴露了 Dog 和 Cat class 一样,通过在 main class 中直接使用 new 来暴露它们)。如果您满意,请点赞。