方法链,从列表中返回一个对象并从中获取值

method chaining, returning an object from a list and getting values from it

我有一个 Dog 对象列表,在这些对象中包含一个布尔值,用于显示狗是否完成了训练。我想做的是遍历列表,并且只遍历 return Dog() 已完成训练的对象,例如,如果它们是 12 只狗,并且只有 3 只狗已完成训练,则循环应该只打印这些对象。

else if (input == 1) {
    for (int i = 0; i < 12; ++i) {
            //Create a temporary value to hold the object.
            Object tempHold = dogKennel.getAnimal(i);
            //If animal has not graduated, skip, else print.
            if (!(tempHold.getGraduation())) {
              continue;
            }
            else {
                  System.out.println(dogKennel);
        }
}

getAnimal(i) returns int i 处的对象

方法 .getGraduation 已定义并执行 return 布尔值,但是编译器不想按原样识别临时值,并且不会超出该值。编译器一直建议转换 tempHold,但即使我这样做了,它也不起作用。

我觉得如果我能让它编译的话它会起作用,因为 returned 的对象会有一个 getGraduation() 方法(它是为超级 class 定义的动物。)

如果您只想过滤具有特定条件的列表,目前最常用的方法是使用 Stream::filter 方法。

看起来像这样:

List<Dog> completedTraining = 
    dogKennel
    .stream()
    .filter(
        dog -> !dog.getGraduation()
    )
    .collect(
        Collectors.toList()
    )
;

正如其他人所说,getGraduation() 方法大概只在 Dog class 中定义。这意味着该方法只能在类型为 Dog 的对象上调用。要定义类型为 Dog 的变量,您可以执行 Dog temphold = *whatever*。它要你强制转换的原因是因为 Object 是 Dog 的超类型。如果你想阅读更多关于转换的信息,你可以在这里:https://javarevisited.blogspot.com/2012/12/what-is-type-casting-in-java-class-interface-example.html

基本上,您所要做的就是转换对象

if (!(((Dog)tempHold).getGraduation())) 
{
    continue;
}

此转换告诉编译器,即使 tempHoldObject class 的对象,它也是 Dog class 的对象并且应该具有它的所有属性

however the compiler doesn't want to recognize temp value as is, ...the compiler keeps suggesting to cast tempHold, but even if I do, it doesn't work.

编译器告诉你两件事:

  1. 一个Object不是一个Dog(反之亦然。一个Dog是一个Object)。
  2. class Object 没有为它们定义方法 isGraduated()

要解决此问题,您可以将 Object 转换为 Dog:

Dog tempHold = (Dog)dogKennel.getAnimal(i);

现在我们有了 Dog,我们可以安全地对其调用 isGraduated()。但问题是我们不能确定我们有 Dog。如果我们从另一个犬舍得到 Animal,我们也可能有一个 Cat。在这种情况下,您将得到一个 ClassCastException,告诉您 Cats 不能转换为 Dogs。

为避免出现 运行 时间异常,您可以添加检查:

Object tempHold = dogKennel.getAnimal(i);
if(tempHold instanceof Dog) {
    Dog dog = (Dog)tempHold;
    System.out.println(dog.isGraduated());
}

instanceof 检查解决了问题。

有一些方法可以完全避免这种 运行 时间检查。一种是创建一个接口:

public interface CanGraduate {
    default boolean isGraduated() {
        return false;
    };
}

然后让所有Animal实现这个接口:

public abstract class Animal implements CanGraduate {
//Behavior common among all animals
}

您现在可以自由添加新的动物类型,并且放心,您可以安全地对它们调用 isGraduated() 并获得 false 值,只要它们继承上述 Animal class.

对于狗来说,isGraduated()应该更有意义。所以你可以在他们的情况下覆盖它:

public class Dog extends Animal {
    private boolean _graduated = true;

    @Override
    public boolean isGraduated() {
        return _graduated; //or some complex logic that determines graduation
    }
}

有了这个结构,你再也不用担心调用任何类型的方法了Animal

举个例子,让我们看一些驱动程序代码:

public class Main {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        Dog dog2 = new Dog();
        Cat cat1 = new Cat();
        Cat cat2 = new Cat();

        List<Animal> dogKennel = List.of(dog1, dog2);
        List<Animal> catKennel = List.of(cat1, cat2);

        for(Animal x : catKennel) {
            System.out.println(x.isGraduated());
        }
    }
}

程序将简单地输出 false,因为 Cats 永远不会毕业。如果 kennel 包含 Dogs,它将输出狗的实际毕业状态。