抽象类和泛型中“ this”关键字的行为

时间:2018-07-31 06:35:50

标签: java generics this abstract-class

请考虑以下课程

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

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”关键字的类型为Animal,并且有界通配符泛型<? extends Animal>仅支持类型为Animal的子类,而不支持Animal类型本身。

我认为编译器应该知道,this关键字的类型必须是扩展Animal的对象(假设无法实例化Animal),而{{1} }关键字仅适用于已存在的对象。

编译器为什么不知道这一点?我的猜测是,有一种情况可以解释为什么不能保证this关键字是Animal的子类。

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

2 个答案:

答案 0 :(得分:2)

您的serializer通用类型是? extends Animal。您的this类型为Animal,也可以视为? extends Animal。但是,这两个?是不同的类型。没有限制让编译器知道它们是同一类型。

例如,我写了一个Cat

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

这就是为什么编译器会给您一个错误。

答案 1 :(得分:0)

除了Dean所说的: 您可以将Animal设为通用:Animal<S extends Animal> 然后,序列化器变为AnimalSerializer<S> serializer。现在,它引用了Animal的“已知”子类。 并且扩展名变成Dog extends Animal<Dog>。不幸的是,无法阻止Cat extends Animal<Dog>

您仍然必须强制执行以下行:serializer.writeAnimal((S)this); 但是现在可以这样做,因为您知道要强制转换为哪个类。

这是泛型?的缺点。