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

omvjsjqw  于 2021-07-04  发布在  Java
关注(0)|答案(1)|浏览(441)

我试图建立一个数据库模型。
我有三个数据库、模式和表的抽象类。每个数据库应该能够返回所有模式,每个模式应该能够返回所有表。接下来,我为一个数据库创建了示例,其中有两个模式,每个模式都包含to表。
抽象类具有类型参数,以确保不同数据库的模式类型不会混合。所有数据库的模式都应该是模式,但是一个特定数据库的特定模式不应该在另一个数据库中使用,而应该在它自己的数据库中使用。
代码如下:

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
  {
  }
}

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

main.java:26: error: schemas() in Database_1 cannot override schemas() in Database
    public List<Schema<Database_1>> schemas () {
                                    ^
  return type List<Schema<Database_1>> is not compatible with List<Schema<? extends Database>>

类型 List<Schema<Database_1>>Database_1 延伸 Database 不兼容: List<Schema<? extends Database>> .
为什么?这个看起来很像。第一个是第二个的子集。为什么不能用具体类的特定类型来满足抽象类的一般要求?

r8xiu3jd

r8xiu3jd1#

Cat 是的一个子类型 Animal . 然后我们写猫≺ 动物。让 PersianCat 是的一个子类型 Cat 因此波斯≺ 猫。
关系是可传递的。波斯≺ 猫和猫≺ 动物=>波斯≺ 动物。这种关系是反身的(猫≺ cat),但不是对称的(cat≺ 动物并不意味着动物≺ 猫)。因此,这种关系是一种秩序。
不变性
但是,泛型类型是不变的。 List<Cat> 根本不是 List<Animal> ,考虑到以下代码段,这是有充分理由的:

List<Animal> animals = new List<Animal>();
animals.add(new Dog());
animals.add(new Cat());

让我们假设一下 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?

因此,泛型是不变的。它们都能保证你能在它们里面投入什么,你能从中得到什么。您可以通过使用co或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

协方差
我们可以使用 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);
``` `List<? extends Cat> cats = new ArrayList<Animal>();` 是一个编译器错误,因为你可以取出任何动物-但你要求唯一可以取出的是猫。
你的代码和错误

return type List<Schema<Database_1>> is not compatible with List<Schema<? extends Database>>
``` Schema<Database_1> 不是的子类型 Schema<? extends Database> . Schema<? extends Database> 必须接受任何类型的t≺ 数据库。然而, Schema<Database_1> 只接受包含t的类型≺ 数据库1。
请考虑以下代码段:

Schema<? extends Database> schema = new Schema<>(new Database_2()); // perfectly valid
List<Schema<? extends Database>> schemas_N = new ArrayList<>();
schemas_N.add(schema); // perfectly valid

List<Schema<Database_1>> schemas_1 = new ArrayList<>();
schemas_1.add(schema); // error, as expected!

// but this is also expected
schemas_N = schemas_1; // error

最后一行现在应该清楚了。我们不能分配 schemas_N 名单 schemas_1 ,因为两者都期望不同的类型。他们根本不相容。
因此,如果您的方法预期返回 List<Schema<? extends Database>> (这意味着你可以 Schema<Database_2> 你不能退回 List<Schema<Database_1>> ,因为它不接受上述类型。重写方法时,不能以不兼容的方式更改它们,因此会出现以下错误:

return type List<Schema<Database_1>> is not compatible with List<Schema<? extends Database>>

相关问题