实现抽象类的类的类型与抽象类的泛型类型不兼容

cev*_*ing 1 java

我试图建模一个数据库。

我有数据库、模式和表的三个抽象类。每个数据库都应该能够返回所有模式,每个模式都应该能够返回所有表。接下来,我为一个数据库创建了实例,其中包含两个模式,每个模式都包含表。

抽象类具有类型参数以确保不同数据库的模式类型不会混合。所有数据库的schema都应该是schema,但是一个特定数据库的特定schema不应该用在另一个数据库中,只能用在它自己的数据库中。

这是代码:

import java.util.List;

public class main
{
  // Abstract

  static abstract class Database
  {
    public abstract List<Schema<? extends Database>> schemas ();
  }

  static abstract class Schema<D extends Database>
  {
    public abstract List<Table<D,? extends Schema<D>>> tables ();
  }

  public abstract class Table<D extends Database,S extends Schema<D>>
  {
  }

  // Concrete

  static class Database_1 extends Database
  {
    @Override
    public List<Schema<Database_1>> schemas () {
      return List.of (new Database_1_Schema_1(),
                      new Database_1_Schema_2());
    }
  }

  static class Database_1_Schema_1 extends Schema<Database_1>
  {
    @Override
    public List<Table<Database_1, Database_1_Schema_1>> tables () {
      return List.of (new Database_1_Schema_1_Table_1(),
                      new Database_1_Schema_1_Table_2());
    }
  }

  static class Database_1_Schema_1_Table_1 extends Table<Database_1, Database_1_Schema_1> { }
  static class Database_1_Schema_1_Table_2 extends Table<Database_1, Database_1_Schema_1> { }

  static class Database_1_Schema_2 extends Schema<Database_1>
  {
    @Override
    public List<Table<Database_1, Database_1_Schema_2>> tables () {
      return List.of (new Database_1_Schema_2_Table_1(),
                      new Database_1_Schema_2_Table_2());
    }
  }

  static class Database_1_Schema_2_Table_1 extends Table<Database_1, Database_1_Schema_2> { }
  static class Database_1_Schema_2_Table_2 extends Table<Database_1, Database_1_Schema_2> { }

  // Main

  public static void main (String ...arguments) throws Exception
  {
  }
}
Run Code Online (Sandbox Code Playgroud)

代码无法编译。当我尝试编译它时,我收到了几个错误。它们中的大多数是间接错误。我不明白的主要错误如下:

import java.util.List;

public class main
{
  // Abstract

  static abstract class Database
  {
    public abstract List<Schema<? extends Database>> schemas ();
  }

  static abstract class Schema<D extends Database>
  {
    public abstract List<Table<D,? extends Schema<D>>> tables ();
  }

  public abstract class Table<D extends Database,S extends Schema<D>>
  {
  }

  // Concrete

  static class Database_1 extends Database
  {
    @Override
    public List<Schema<Database_1>> schemas () {
      return List.of (new Database_1_Schema_1(),
                      new Database_1_Schema_2());
    }
  }

  static class Database_1_Schema_1 extends Schema<Database_1>
  {
    @Override
    public List<Table<Database_1, Database_1_Schema_1>> tables () {
      return List.of (new Database_1_Schema_1_Table_1(),
                      new Database_1_Schema_1_Table_2());
    }
  }

  static class Database_1_Schema_1_Table_1 extends Table<Database_1, Database_1_Schema_1> { }
  static class Database_1_Schema_1_Table_2 extends Table<Database_1, Database_1_Schema_1> { }

  static class Database_1_Schema_2 extends Schema<Database_1>
  {
    @Override
    public List<Table<Database_1, Database_1_Schema_2>> tables () {
      return List.of (new Database_1_Schema_2_Table_1(),
                      new Database_1_Schema_2_Table_2());
    }
  }

  static class Database_1_Schema_2_Table_1 extends Table<Database_1, Database_1_Schema_2> { }
  static class Database_1_Schema_2_Table_2 extends Table<Database_1, Database_1_Schema_2> { }

  // Main

  public static void main (String ...arguments) throws Exception
  {
  }
}
Run Code Online (Sandbox Code Playgroud)

方式

  • List<Schema<Database_1>>Database_1扩展Database

不兼容:

  • List<Schema<? extends Database>>.

为什么?外观非常相似。第一个是第二个的子集。为什么用具体类的具体类型不能满足抽象类的一般要求?

Pol*_*ome 6

Cat成为 的子类型Animal。然后我们写 Cat ? 动物。让PersianCat是 的子类型Cat,因此 PersianCat ?猫。

该关系是可传递的。波斯猫?猫&&猫?动物 => 波斯猫?动物。这种关系是自反的(猫?猫),但不是对称的(猫?动物不暗示动物?猫)。因此,该关系是一个订单

不变性

然而,泛型类型是不变的。List<Cat>根本不是的子类型List<Animal>,并且有充分的理由,考虑以下代码片段:

List<Animal> animals = new List<Animal>();
animals.add(new Dog());
animals.add(new Cat());
Run Code Online (Sandbox Code Playgroud)

让我们假设一下List<Cat>List<Animal>并重新考虑稍加改动的代码片段:

List<Animal> animals = new List<Cat>(); // valid, since List<Cat> ? List<Animal>
animals.add(new Cat());
animals.add(new Dog()); // bäng! But I am allowed to put Dogs into List<Animal>, no?
Run Code Online (Sandbox Code Playgroud)

因此,泛型是不变的。它们都保证您可以放入它们并从中得到什么。您可以通过使用 Co-or Contarvariant 类型边界来简化这些要求。

逆变

List<? super Dog>逆变的。我们只能把狗放进去,但没有说我们出去的东西。因此,我们得到 Object ,因为它是类型层次结构的根(它是我们子类型关系中最大的元素,顺序的最高点)。

List<? super Dog> dogs = new ArrayList<Animal>();这是有效的,因为我们可以将狗放入其中。动物是物体,所以我们可以取出物体。

List<? super Dog> dogs = new ArrayList<Animal>();
// dogs.add(new Animal()); // compile error, need to put Dog in
dogs.add(new Dog());
Object obj = dogs.get(0);
// Dog dog = dogs.get(0); // compile error, can only take Object out
Run Code Online (Sandbox Code Playgroud)

协方差

我们可以使用使类型协变extends。协变类型保证了你可以类型中得到什么。

List<? extends Animal>协变的。你肯定可以得到一个动物出来

List<? extends Animal> animals = new ArrayList<Cat>();是允许的,因为猫是动物,(猫?动物)并get(int)给你动物。当然,他们都是猫,但猫是动物,所以这很好。

但是,添加东西更难,因为您实际上没有可以放入的类型:

List<? extends Animal> animals = new ArrayList<Cat>();
//animals.add(new Cat()); // compile error
//animals.add(new Animal()); // compile error
Animal animal = animals.get(0);
Run Code Online (Sandbox Code Playgroud)

List<? extends Cat> cats = new ArrayList<Animal>();是一个编译器错误,因为您可以取出任何动物 - 但您要求唯一可以取出的是 Cats。

你的代码和错误

return type List<Schema<Database_1>> is not compatible with List<Schema<? extends Database>>
Run Code Online (Sandbox Code Playgroud)

Schema<Database_1> 不是 的子类型Schema<? extends Database>Schema<? extends Database>必须接受持有 T 的任何类型 T ?数据库。但是,Schema<Database_1> 接受包含 T 的类型?数据库_1。

考虑以下代码片段:

return type List<Schema<Database_1>> is not compatible with List<Schema<? extends Database>>
Run Code Online (Sandbox Code Playgroud)

最后一行现在应该很清楚了。我们不能分配schemas_Nlist schemas_1,因为两者都期望不同的类型。它们根本不兼容。

因此,如果您的方法预期返回 a List<Schema<? extends Database>>(这意味着您可以将 aSchema<Database_2>放入其中),则不能返回 a List<Schema<Database_1>>,因为它不接受上述类型。覆盖方法时,您不能以不兼容的方式更改它们,因此您会看到以下错误:

return type List<Schema<Database_1>> is not compatible with List<Schema<? extends Database>>
Run Code Online (Sandbox Code Playgroud)