代码之家  ›  专栏  ›  技术社区  ›  CHess

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

  •  0
  • CHess  · 技术社区  · 8 年前

    考虑以下几类

    就连载而言,我知道:

    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的子类。

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

    2 回复  |  直到 8 年前
        1
  •  2
  •   matt    8 年前

    你的 serializer 泛型类型为 ? extends Animal . 你的 this 类型为 Animal ,也可以认为是 ? 扩展动物 . 但这两个 ? 是不同的类型。不存在让编译器知道它们是同一类型的约束。

    例如,我写了一个 Cat 班

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

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

        2
  •  0
  •   jokster    8 年前

    除了迪恩说的: 你可以 Animal 通用: Animal<S extends Animal> 然后序列化程序变成 AnimalSerializer<S> serializer . 现在它引用了一个“已知”的动物亚纲。 延伸就变成 Dog extends Animal<Dog> . 不幸的是,没有办法阻止 Cat extends Animal<Dog> .

    你还得把这句冒犯的台词加进去: serializer.writeAnimal((S)this); 但现在可以这么做了,因为你知道该投哪个类。

    这是 ? 在泛型中。