首页 > 解决方案 > 抽象类和泛型中“this”关键字的行为

问题描述

考虑以下类

就序列化而言,重新发明轮子,我知道:

abstract class AnimalSerializer<E extends Animal> {
    /**
     * The type E (which extends Animal) is important here. 
     * I want to be able to write data that is specific to a subclass of an animal.
     */
    abstract void writeAnimal(E animal);
    abstract Animal readAnimal();
}

abstract class Animal {
    AnimalSerializer<? extends Animal> serializer;

    Animal(AnimalSerializer<? extends Animal> speciesSerializer) {
        serializer = speciesSerializer;
    }

    void writeAnimalToFile() {
        // This line fails to compile
        serializer.writeAnimal(this);
    }
}

这些类演示了这种模式的使用:

class DogSerializer extends AnimalSerializer<Dog> {

    @Override
    void writeAnimal(Dog animal) {
        // Write the stuff that is specific to the dog
        // ...
    }

    @Override
    Animal readAnimal() {
        // Read the stuff specific to the dog, instantiate it, and cast it as an animal.
        // ...
        return null;
    }  
}

class Dog extends Animal {
    String dogTag = "Data specific to dog.";

    Dog() {
        super(new DogSerializer());
    }
}

我的问题与编译失败的行有关(serializer.writeAnimal(this))。我不得不第一次查阅语言规范以了解更多关于this关键字的信息,但我认为问题在于“this”关键字属于 type Animal,而有界通配符泛型<? extends Animal>仅支持作为 Animal 子类的类型,不是Animal类型本身。

我认为编译器应该知道this关键字的类型必须是扩展 Animal 的对象,因为 Animal 不能被实例化,并且this关键字仅适用于已经存在的对象。

编译器是否有理由不知道这一点?我的猜测是,有一个案例可以解释为什么this不能保证关键字是 Animal 的子类。

此外,这种模式是否存在根本缺陷?

标签: javagenericsthisabstract-class

解决方案


您的serializer通用类型是? extends Animal. 你的this类型是Animal,也可以认为是? extends Animal。但这两种?是不同的类型。没有约束让编译器知道它们是相同的类型。

比如我写了一个Cat

class Cat extends Animal {
  Cat(){
    super(new DogSerializer()); // this is ok for your generic
  }
}

这就是编译器给你一个错误的原因。


推荐阅读