ArrayList和检索对象时的非特异性

时间:2015-01-11 10:38:26

标签: java arraylist

首先对这个问题道歉 - 我是Java的新手,并且想不出用它来表达的好方法。

我有一个名为" Animal"的抽象类。还有一些叫做" Pig"," Horse"继承自" Animal"。

的等等

我正在使用ArrayList来创建一个动物列表,这些动物是实例化的Pigs,Horses等。然后我想将动物从列表中拉出来并使用它们,但是Java只允许我与它们进行交互,如果它们是基类,Animal。

以下是我的主要代码的快速列表,应该更清楚:

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {

        ArrayList<Animal> animals = new ArrayList<Animal>();
        animals.add(new Pig("Porkey", "pink"));
        Animal animal = animals.get(0);
        animal.introAnimal(animal);
        animal.oink(); // Won't compile.Specific Pig class method   
    }
}

现在我知道我可以使用&#34; Pig animal = (Pig) animals.get(0)&#34;但我的观点是,我希望能够与这些动物一起工作而不管它们是什么,如果我需要知道的话,可以使用getObjectType或稍后使用它。

看起来好像这是多态性的障碍:)我不太担心这个特定的代码(我只是在练习),但更多的是在这个问题的一般解决方案中。

非常感谢。

3 个答案:

答案 0 :(得分:5)

您必须使用动物通用的术语。而不是指示动物oink不适用于所有动物,你可以指示speak这可能是一个通用术语。

Java是一种静态类型语言,因此如果您尝试使用可能在运行时无效的方法,编译器会抱怨。它不是一种动态语言,它允许您调用任何方法,希望它可以在运行时工作。虽然这更灵活,但是可靠地构建大型程序更加困难。例如说我重命名一个方法,我怎么知道谁调用该方法也重命名它。

abstract class Animal {
    void speak();
}

class Pig extends Animal {
    public void speak() {
        System.out.println("Oink");
    }
}

class Dog extends Animal {
    public void speak() {
        System.out.println("Woof");
    }
}

class Duck extends Animal {
    public void speak() {
        System.out.println("Qwack");
    }
}

List<Animal> animals = Arrays.<Animal>asList(new Dog(), new Pig(), new Duck);
for (Animal animal : animals)
    animal.speak();

打印

Woof
Oink
Qwack
  

感谢您的回答。我试图得到的是,我希望能够创建一个列表,然后从列表中删除东西,并能够处理子类,具体取决于它在运行时的子类。我只是没有意识到你可以稍后再去获取子类方法。

有两种方法可以做到这一点。

List<Animal> animals = ...
for (Animal animal: animals)
    if (animal instanceof Pig) {
        ((Pig) animal).oink();
    }

这仍然要求你知道你想养猪。假设你有另一个班级Boar并且它也有一个oink方法,而你并不关心Pig和Boar没有父类(尽管你可以)

List<Animal> animals = ...
for (Animal animal: animals) {
    Method method = animal.getClass().getMethod("oink");
    if (method != null)
        method.invoke(animal);
}

现在让我们说这个方法不仅不在Animal中,而且对于猪来说它是private,这使得它更难调用。

List<Animal> animals = ...
for (Animal animal: animals) {
    Method method = animal.getClass().getDeclaredMethod("oink");
    if (method != null) {
        method.setAccessible(true);
        method.invoke(animal);
    }
}

答案 1 :(得分:4)

您可以使用instanceof运算符(instanceof关键字可用于测试对象是否为指定类型。)以检查animal是否引用Pig以及是否 ArrayList<Animal> animals = new ArrayList<Animal>(); animals.add(new Pig("Porkey", "pink")); Animal animal = animals.get(0); animal.introAnimal(animal); if (animal instanceof Pig) ((Pig)animal).oink(); // This will compile and work ,然后执行演员并调用Pig的特定方法。 E.g。

{{1}}

答案 2 :(得分:1)

如果超类包含一个方法execute(),并且你在每个子类型中实现了这个函数,那么将执行正确的方法。

示例:

class pig extends Animal {
    ...
    public void execute () {
        System.out.println("Oink");
    }
    public void specificPigAction {
        ... 
   }
}

class cat extends Animal {
    ...
    public void execute () {
        System.out.println("Meow");
    }
}

现在你可以这样做:

Animal pig = animals.get();
pig.execute(); // output = oink
Animal cat = animals.get();
cat.execute(); // output = meow

如果您希望执行非常具体的任务,可能只有猫,您必须将对象强制转换为正确的类型:

Pig pig = (Pig) animals.get();
pig.specificPigAction();

在后一种情况下,只有在知道类型正确或将其包含在throw catch子句中时,才能进行强制转换。

请注意,此代码可能不符合样式规则甚至Java语法,但我相信这个想法很明确。