通配符<?>
首先,先看如下实例
Employee类
- public class Employee {
- private String name;
- public String getname() {
- return name;
- }
- public void setname(String name) {
- this.name = name;
- }
- }
Manager类继承Employee类
- public class Manager extends Employee {
- @Override
- public String getname() {
- return ("Manager :"+ super.getname());
- }
- }
编写一个泛型Person类
- public class Person<T > {
- private T name;
- public Person(T name) {
- super();
- this.name = name;
- }
- public Person() {
- super();
- }
- public T getName() {
- return name;
- }
- public void setName(T name) {
- this.name = name;
- }
- }
编写一个测试类GenericInheritDome
- public class GenericInheritDome {
- public static void main(String[] args) {
- Person<Manager> name1= new Person<Manager>(new Manager());
- Person<Employee> name2=name1;
- name2.getName().setname("singsong");
- System.out.println(name2.getName().getname()) ;
- }
- }
无法编译,提示错误cannot convert from Person<Manager> to Person<Employee>
无法进行类型转换错误。Person<Employee> name2=name1;
也就是此时的Person<Manager>与Person<>Employee>没有继承关系,不符合java的置换原则
(一个指定类型的变量可以被赋值为该类型的任何子类;一个指定某种类型参数的方法可以通过传入该类型的子类来进行调用。也就是说我们使用的任何类型变量都可以用该类型的子类型来替换)
把Person<Employee> name2=name1;改成Person<? extends Employee> name2=name1;
代码改如下:
- public class GenericInheritDome {
- public static void main(String[] args) {
- Person<Manager> name1= new Person<Manager>(new Manager());
- Person<? extends Employee> name2=name1;
- name2.getName().setName("singsong");
- System.out.println(name2.getName().getName()) ;
- }
- }
可以编译了!
运行结果:Manager :singsong
不能这样使用
void setName(? extends Employee)
但是可以这样使用:
? extends Employee getName()
因为编译器只知道需要某个Employee的子类型,但不知道具体是什么类型。它拒接传递任何特定的类型。
但使用getName就不存在这个问题了,因为将getName的返回值赋给一个Employee的引用完全合法。
? super Manager 与? Extends Employee恰好相反。可以为方法提供参数,但是不能使用返回值。
即可以这样调用void setName(? super Manager)
而不能调用? super Manager getName(),这样是不完全的。
因为setName 可以任意的Manager对象,或者超类调用,而参数符合置换原则。
但是调用getName(),返回的对象类型就不会得到保证。只能把它赋给一个Object。
总的来说:带有超类型限定的通配符可以向泛型对象写入。带有子类型限定的通配符可以从泛型对象读取
实例:
- public class Test {
- public void executeGetFun(String name, Person<? extends Employee> p) {
- Employee employee = p.getName();
- employee.setname(name);//可以正常运行
- System.out.println(employee.getname());
- // p.setName(new Employee());//error:The method setName(capture#2-of ? extends Employee) in the type
- //Person<capture#2-of ? extends Employee> is not applicable
- //for the arguments (Employee)
- }
- public void executeSetFun(Person<? super Manager> p) {
- Manager manager = new Manager();
- manager.setname("Set--<super>--singsong");
- p.setName(new Manager());//可以正常运行
- System.out.println(manager.getname());
- // Manager manager1=p.getName();//error:Type mismatch: cannot convert from capture#3-of ?
- //super Manager to Manager
- }
- public static void main(String[] args) {
- Test test = new Test();
- Person<Manager> name1 = new Person<Manager>(new Manager());
- test.executeGetFun("Get--<extends>--singsong", name1);
- test.executeSetFun(name1);
- }
- }
运行结果:
Manager :Get--<extends>--singsong
Manager :Set--<super>--singsong
若没有限定通配符时,只可以从泛型对象读取,而不能向泛型对象写入。
? getName()√
Void setName(?)×
Person<?>与Person原型的区别,可以用任意Object对象调用原始的Person类的setName方法。
通配符不是类型变量,因此,不能再编写代码中使用“?”作为一种类型。