我试图建模一个数据库。
我有数据库、模式和表的三个抽象类。每个数据库都应该能够返回所有模式,每个模式都应该能够返回所有表。接下来,我为一个数据库创建了实例,其中包含两个模式,每个模式都包含表。
抽象类具有类型参数以确保不同数据库的模式类型不会混合。所有数据库的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>>.为什么?外观非常相似。第一个是第二个的子集。为什么用具体类的具体类型不能满足抽象类的一般要求?
让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)
| 归档时间: |
|
| 查看次数: |
71 次 |
| 最近记录: |