通配符的使用

本文详细介绍了Java中的泛型和类型通配符,包括通配符的使用、注意事项,以及在实际编程中的应用实例,如泛型嵌套和信息类设计。
摘要由CSDN通过智能技术生成

当我们声明一个变量/形参时,这个变量/形参的类型是一个泛型类或泛型接口,例如:Comparator<T>类型,但是我们仍然无法确定这个泛型类或泛型接口的类型变量<T>的具体类型,此时我们考虑使用类型通配符 ? 。

5.1 通配符的理解

使用类型通配符:?

比如:List<?>Map<?,?>

List<?>List<String>List<Object>等各种泛型List的父类。

5.2 通配符的读与写

写操作:

将任意元素加入到其中不是类型安全的:

Collection<?> c = new ArrayList<String>();
​
c.add(new Object()); // 编译时错误

因为我们不知道c的元素类型,我们不能向其中添加对象。add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。

唯一可以插入的元素是null,因为它是所有引用类型的默认值。

读操作:

另一方面,读取List<?>的对象list中的元素时,永远是安全的,因为不管 list 的真实类型是什么,它包含的都是Object。

举例1:

public class TestWildcard {
    public static void m4(Collection<?> coll){
        for (Object o : coll) {
            System.out.println(o);
        }
    }
}

举例2:

public static void main(String[] args) {
    List<?> list = null;
    list = new ArrayList<String>();
    list = new ArrayList<Double>();
    // list.add(3);//编译不通过
    list.add(null);
​
    List<String> l1 = new ArrayList<String>();
    List<Integer> l2 = new ArrayList<Integer>();
    l1.add("尚硅谷");
    l2.add(15);
    read(l1);
    read(l2);
}
​
public static void read(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
}
​

5.3 使用注意点

注意点1:编译错误:不能用在泛型方法声明上,返回值类型前面<>不能使用?

public static <?> void test(ArrayList<?> list){
}

注意点2:编译错误:不能用在泛型类的声明上

class GenericTypeClass<?>{
}

注意点3:编译错误:不能用在创建对象上,右边属于创建集合对象

ArrayList<?> list2 = new ArrayList<?>();

5.4 有限制的通配符

  • <?>

    • 允许所有泛型的引用调用

  • 通配符指定上限:<? extends 类/接口 >

    • 使用时指定的类型必须是继承某个类,或者实现某个接口,即<=

  • 通配符指定下限:<? super 类/接口 >

    • 使用时指定的类型必须是操作的类或接口,或者是操作的类的父类或接口的父接口,即>=

  • 说明:

    <? extends Number>     //(无穷小 , Number]
    //只允许泛型为Number及Number子类的引用调用
    ​
    <? super Number>      //[Number , 无穷大)
    //只允许泛型为Number及Number父类的引用调用
    ​
    <? extends Comparable>
    //只允许泛型为实现Comparable接口的实现类的引用调用
  • 举例1

    class Creature{}
    class Person extends Creature{}
    class Man extends Person{}
    ​
    class PersonTest {
        public static <T extends Person> void test(T t){
            System.out.println(t);
        }
    ​
        public static void main(String[] args) {
            test(new Person());
            test(new Man());
            //The method test(T) in the type PersonTest is not 
            //applicable for the arguments (Creature)
            test(new Creature());
        }
    }
    ​
  • 举例2:

    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<Integer>();
        Collection<String> list2 = new ArrayList<String>();
        Collection<Number> list3 = new ArrayList<Number>();
        Collection<Object> list4 = new ArrayList<Object>();
        
        getElement1(list1);
        getElement1(list2);//报错
        getElement1(list3);
        getElement1(list4);//报错
      
        getElement2(list1);//报错
        getElement2(list2);//报错
        getElement2(list3);
        getElement2(list4);
      
    }
    // 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
    public static void getElement1(Collection<? extends Number> coll){}
    // 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
    public static void getElement2(Collection<? super Number> coll){}
  • 举例3:

    public static void printCollection1(Collection<? extends Person> coll) {
        //Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
        Iterator<?> iterator = coll.iterator();
        while (iterator.hasNext()) {
            Person per = iterator.next();
            System.out.println(per);
        }
    }
    ​
    public static void printCollection2(Collection<? super Person> coll) {
        //Iterator只能用Iterator<?>或Iterator<? super Person>.why?
        Iterator<?> iterator = coll.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }
    ​

举例4:

@Test
public void test1(){
    //List<Object> list1 = null;
    List<Person> list2 = new ArrayList<Person>();
    //List<Student> list3 = null;
​
    List<? extends Person> list4 = null;
​
    list2.add(new Person());
    list4 = list2;
​
    //读取:可以读
    Person p1 = list4.get(0);
​
    //写入:除了null之外,不能写入
    list4.add(null);
    //        list4.add(new Person());
    //        list4.add(new Student());
​
}
​
@Test
public void test2(){
    //List<Object> list1 = null;
    List<Person> list2 = new ArrayList<Person>();
    //List<Student> list3 = null;
​
    List<? super Person> list5 = null;
    list2.add(new Person());
​
    list5 = list2;
​
    //读取:可以实现
    Object obj = list5.get(0);
​
    //写入:可以写入Person及Person子类的对象
    list5.add(new Person());
    list5.add(new Student());
​
}

5.5 泛型应用举例

举例1:泛型嵌套

public static void main(String[] args) {
    HashMap<String, ArrayList<Citizen>> map = new HashMap<String, ArrayList<Citizen>>();
    ArrayList<Citizen> list = new ArrayList<Citizen>();
    list.add(new Citizen("赵又廷"));
    list.add(new Citizen("高圆圆"));
    list.add(new Citizen("瑞亚"));
    map.put("赵又廷", list);
​
    Set<Entry<String, ArrayList<Citizen>>> entrySet = map.entrySet();
    Iterator<Entry<String, ArrayList<Citizen>>> iterator = entrySet.iterator();
    while (iterator.hasNext()) {
        Entry<String, ArrayList<Citizen>> entry = iterator.next();
        String key = entry.getKey();
        ArrayList<Citizen> value = entry.getValue();
        System.out.println("户主:" + key);
        System.out.println("家庭成员:" + value);
    }
}
​

举例2:个人信息设计

用户在设计类的时候往往会使用类的关联关系,例如,一个人中可以定义一个信息的属性,但是一个人可能有各种各样的信息(如联系方式、基本信息等),所以此信息属性的类型就可以通过泛型进行声明,然后只要设计相应的信息类即可。

 

interface Info{     // 只有此接口的子类才是表示人的信息
}
class Contact implements Info{  // 表示联系方式
    private String address ;    // 联系地址
    private String telephone ;  // 联系方式
    private String zipcode ;    // 邮政编码
    public Contact(String address,String telephone,String zipcode){
        this.address = address;
        this.telephone = telephone;
        this.zipcode = zipcode;
    }
    public void setAddress(String address){
        this.address = address ;
    }
    public void setTelephone(String telephone){
        this.telephone = telephone ;
    }
    public void setZipcode(String zipcode){
        this.zipcode = zipcode;
    }
    public String getAddress(){
        return this.address ;
    }
    public String getTelephone(){
        return this.telephone ;
    }
    public String getZipcode(){
        return this.zipcode;
    }
    @Override
    public String toString() {
        return "Contact [address=" + address + ", telephone=" + telephone
                + ", zipcode=" + zipcode + "]";
    }
}
class Introduction implements Info{
    private String name ;       // 姓名
    private String sex ;        // 性别
    private int age ;           // 年龄
    public Introduction(String name,String sex,int age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public void setName(String name){
        this.name = name ;
    }
    public void setSex(String sex){
        this.sex = sex ;
    }
    public void setAge(int age){
        this.age = age ;
    }
    public String getName(){
        return this.name ;
    }
    public String getSex(){
        return this.sex ;
    }
    public int getAge(){
        return this.age ;
    }
    @Override
    public String toString() {
        return "Introduction [name=" + name + ", sex=" + sex + ", age=" + age
                + "]";
    }
}
class Person<T extends Info>{
    private T info ;
    public Person(T info){      // 通过构造器设置信息属性内容
        this.info = info;
    }
    public void setInfo(T info){
        this.info = info ;
    }
    public T getInfo(){
        return info ;
    }
    @Override
    public String toString() {
        return "Person [info=" + info + "]";
    }
    
}
public class GenericPerson{
    public static void main(String args[]){
        Person<Contact> per = null ;        // 声明Person对象
        per = new Person<Contact>(new Contact("北京市","01088888888","102206")) ;
        System.out.println(per);
        
        Person<Introduction> per2 = null ;      // 声明Person对象
        per2 = new Person<Introduction>(new Introduction("李雷","男",24));
        System.out.println(per2) ;
    }
}

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
find命令支持通配符使用。在find命令中,通配符可以用于匹配文件名。引用[2]中提到,对于find命令中的-name选项后面的参数,可以使用通配符*进行模糊匹配。需要注意的是,为了确保通配符不被bash预先扩展,需要将通配符*加上引号。这样find命令才能正确接收到通配符作为参数。其他命令可能不支持通配符使用,比如ls命令。而在find命令中,通配符会被find命令自身解析,并在指定目录及其子目录中寻找匹配的文件。例如,find . -name "abc*"会在当前目录及其子目录中寻找以abc开头的文件。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [系统学习----通配符及find命令](https://blog.csdn.net/weixin_46097280/article/details/104291374)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [ls命令和find命令通配符和双引号的使用区别](https://blog.csdn.net/isco22/article/details/89876633)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值