Java拾贝第十天——通配符与泛型

发布时间 2023-10-24 14:22:48作者: ocraft

Java拾贝不建议作为0基础学习,都是本人想到什么写什么

现有如下栗子:

public class Test10 {
    public static void main(String[] args) {
        Gen<String> gen = new Gen<>();
        tell(gen);
    }
    public static void tell(Gen<Object> gen) {//普通方法使用泛型作为传参
        System.out.println("泛型使用Object,理论上接收所有类型的gen");
    }
}

class Gen<T> {}//泛型类

程序运行结果:

java: 不兼容的类型: moudle1.Gen<java.lang.String>
无法转换为moudle1.Gen<java.lang.Object>

尽管String是Object的子类,但泛型指定了类型后,编译器会严格检查传参的合法性。

想要上述栗子得以编译通过可以修改:

    public static void tell(Gen gen) {//即不指定类型
        System.out.println("不指定泛型类型,但会导致泛型擦除");
    }

至此编译确实可以通过,但这不是好的解决办法。

为此Java提供了通配符

通配符

通配符表示可以接收任意泛型对象。通配符表示为<?>

修改栗子:

public class Test10 {
    public static void main(String[] args) {
        Gen<String> gen1 = new Gen<>();
        tell(gen1);
        Gen<Integer> gen2 = new Gen<>();
        tell(gen2);
        Gen<Boolean> gen3 = new Gen<>();
        tell(gen3);
    }
    public static void tell(Gen<?> gen) {//使用通配符
        System.out.println("使用通配符,可以传入任意类型"+gen);
    }
}

class Gen<T> {}

程序运行结果:

使用通配符,可以传入任意类型moudle1.Gen@1b6d3586
使用通配符,可以传入任意类型moudle1.Gen@4554617c
使用通配符,可以传入任意类型moudle1.Gen@74a14482
//因为没有重写Gen类的toString()方法所以默认打印对象地址值

通配符不可作为泛型类的指定类型

public class Test10 {
    public static void main(String[] args) {
        Gen<?> gen = new Gen<?>();//编译错误
    }
}
class Gen<T> {}

上述写法JVM无法完成初始化。

下述写法也是错误

class Gen<?> {
    private ? name;
}

因为JVM碰到<?>只会把它当作通配符,不能作为泛型使用。

受限泛型

泛型是任意数据类型,有时候想人为的限制泛型类型可以使用受限泛型

受限泛型基于通配符,有以下两种:

<? extends 类名>
<? super 类名>

<? extends 类名>

当使用的泛型只能是某类和其子类,可以使用此受限泛型:

public class Test10 {
    public static void main(String[] args) {
        Gen<AA> gen1 = new Gen<>();
        Gen<BB> gen2 = new Gen<>();
        Gen<CC> gen3 = new Gen<>();
        Gen<DD> gen4 = new Gen<>();
        say(gen1);
        say(gen2);
        say(gen3);
        say(gen4);//编译错误 DD不是AA子类
    }

    public static void say(Gen<? extends AA> temp) {//extends
        System.out.println("受限泛型为AA和其子类" + temp);
    }

}
class Gen<T>{}

class AA { }
class BB extends AA { }
class CC extends AA{ }
class DD {}

<? super 类名>

当使用的泛型只能是某类和其父类,可以使用此受限泛型:

public class Test10 {
    public static void main(String[] args) {
        Gen<AA> gen1 = new Gen<>();
        Gen<BB> gen2 = new Gen<>();
        Gen<CC> gen3 = new Gen<>();
        Gen<DD> gen4 = new Gen<>();
        Gen<Object> gen5 = new Gen<>();//任何类都继承Object
        say(gen1);
        say(gen2);//编译错误
        say(gen3);//编译错误
        say(gen4);//编译错误
        say(gen5);
    }

    public static void say(Gen<? super AA> temp) {//super
        System.out.println("受限泛型为AA和其父类" + temp);
    }

}
class Gen<T>{}

class AA { }
class BB extends AA { }
class CC extends AA{ }
class DD {}

受限泛型可以作用于泛型类

和泛型类一样

class Gen<T extends AA> {//泛型T只能是AA和其子类
    private T name;
    //...
}

class AA { }
class BB extends AA { }
class CC extends AA { }
class DD { }

受限泛型可以作用于泛型方法

和泛型方法一样

class Gen<T extends AA> {
   private T name;
   public <K extends BB> void Tb(){//泛型方法中自己定义了一个泛型K

   }
    //...
}

嵌套泛型

泛型即广泛的类型,当然可以接收泛型类

public class Test10 {
    public static void main(String[] args) {
        U< P<String, Integer> > pu = new U<>();
    }
}

class U<T> {}//泛型类U 有一个泛型
class P<K,V>{}//泛型类P 有两个泛型