上界通配符
Upperbound wild card
我正在处理 arraylist 中的上限通配符 (?)。当我使用通配符声明数组列表时它不起作用。
例如 :
我有三个 classes:
1) 人 class:
public class Person {
}
2) 员工 class 扩展人:
public class Employee extends Person {
}
3) 扩展员工的部门 class。
public class Dept extends Employee{
}
现在我想将这三个 classes 的对象添加到单独的 class 数组列表中,如下所示。
public class TestPerson {
public static void main(String[] args) {
Person p1 =new Person();
Employee e1 = new Employee();
Dept d1 = new Dept();
ArrayList<? extends Person> al =new ArrayList<Person>();
al.add(p1);
al.add(e1);
al.add(d1);
}
}
代码中的最后三行显示以下错误:
ArrayList 类型中的方法 add(capture#1-of ? extends Person) 不适用于参数(对象类型)。
但是从类型为“?extends person”的数组列表中,可以采用 "any object extends person",但为什么它不接受扩展的员工对象
人.
ArrayList<? extends Person>
可能是 ArrayList<Employee>
。在这种情况下,将不允许您添加非员工。由于编译器不知道类型,因此不允许您添加任何内容。
请注意,编译器确实 知道列表中已有的所有元素都将是Person
的子类。所以 get
即使在 add
不工作时也能工作:
Person x = al.get(0);
如果您想要 List
可以采用三种类型中的任何一种,请使用 ArrayList<Person>
。
java 泛型是通过 Erasure 的概念实现的,这意味着当您使用泛型时,任何特定的类型信息都会被擦除。在泛型内部,您实际上是在使用 Object 例如 List (List < String >) 和 List (List < Integer >) 在运行时属于同一类型。通用类型仅在 静态类型检查 期间存在,之后程序中的每个通用类型都被 擦除 替换为 非通用上限.
由于擦除删除了类型信息,您只能调用 unbounded 通用参数 的方法是 Object,但如果您可以将该参数限制为 类型 的子集,则可以调用该子集中的方法。要执行此约束 java 泛型使用 extends 关键字。
鉴于此背景,当您指定 ArrayList (ArrayList < ? extends Person >) 时,您实际上是指“从 Person 继承的任何类型的列表”。这并不意味着该列表将包含任何类型的人。通配符 (?) 指的是明确的类型,因此它意味着此列表未指定的某些特定类型(Person 类型)将在列表中。因此该列表可以包含 特定 类型的人,但您不知道那是哪一类人。因此您不能将 Person 类型的对象添加到此列表中。
但是,当您说 ArrayList (? super Person) 时,您说的是此列表包含派生自 Person 的特定对象,即基类或超类型 为 Person 的对象。因此,将一个 Person 或从 Person 派生的任何东西传递到这个列表中是安全的。因此它有效。
希望对您有所帮助!
我正在处理 arraylist 中的上限通配符 (?)。当我使用通配符声明数组列表时它不起作用。 例如 : 我有三个 classes:
1) 人 class:
public class Person {
}
2) 员工 class 扩展人:
public class Employee extends Person {
}
3) 扩展员工的部门 class。
public class Dept extends Employee{
}
现在我想将这三个 classes 的对象添加到单独的 class 数组列表中,如下所示。
public class TestPerson {
public static void main(String[] args) {
Person p1 =new Person();
Employee e1 = new Employee();
Dept d1 = new Dept();
ArrayList<? extends Person> al =new ArrayList<Person>();
al.add(p1);
al.add(e1);
al.add(d1);
}
}
代码中的最后三行显示以下错误: ArrayList 类型中的方法 add(capture#1-of ? extends Person) 不适用于参数(对象类型)。
但是从类型为“?extends person”的数组列表中,可以采用 "any object extends person",但为什么它不接受扩展的员工对象 人.
ArrayList<? extends Person>
可能是 ArrayList<Employee>
。在这种情况下,将不允许您添加非员工。由于编译器不知道类型,因此不允许您添加任何内容。
请注意,编译器确实 知道列表中已有的所有元素都将是Person
的子类。所以 get
即使在 add
不工作时也能工作:
Person x = al.get(0);
如果您想要 List
可以采用三种类型中的任何一种,请使用 ArrayList<Person>
。
java 泛型是通过 Erasure 的概念实现的,这意味着当您使用泛型时,任何特定的类型信息都会被擦除。在泛型内部,您实际上是在使用 Object 例如 List (List < String >) 和 List (List < Integer >) 在运行时属于同一类型。通用类型仅在 静态类型检查 期间存在,之后程序中的每个通用类型都被 擦除 替换为 非通用上限.
由于擦除删除了类型信息,您只能调用 unbounded 通用参数 的方法是 Object,但如果您可以将该参数限制为 类型 的子集,则可以调用该子集中的方法。要执行此约束 java 泛型使用 extends 关键字。
鉴于此背景,当您指定 ArrayList (ArrayList < ? extends Person >) 时,您实际上是指“从 Person 继承的任何类型的列表”。这并不意味着该列表将包含任何类型的人。通配符 (?) 指的是明确的类型,因此它意味着此列表未指定的某些特定类型(Person 类型)将在列表中。因此该列表可以包含 特定 类型的人,但您不知道那是哪一类人。因此您不能将 Person 类型的对象添加到此列表中。
但是,当您说 ArrayList (? super Person) 时,您说的是此列表包含派生自 Person 的特定对象,即基类或超类型 为 Person 的对象。因此,将一个 Person 或从 Person 派生的任何东西传递到这个列表中是安全的。因此它有效。
希望对您有所帮助!