通配符<?>
首先,先看如下實例
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方法。
通配符不是類型變量,因此,不能再編寫代碼中使用“?”作爲一種類型。