• java泛型场景补充注意事项


    前言

    本文不是对泛型的系统介绍,也不打算对其进行入门讲解,只是对遇到的一些泛型场景的补充。看过宋红康和韩顺平的javase课程可以花几分钟看看。

    1.&符号在泛型中的使用,用来描述有边界的受约束泛型

    class A{}
    interface B{}
    public class C< T extends A & B>{}
    
    • 1
    • 2
    • 3

    这里的泛型类型受到约束,既要是A的子类,也要实现B的接口。注意虽然B是接口但是泛型仍要用关键字extends,并且写在A的右边。为什么呢?这与类的定义是一致的,Java允许继承一个类和实现多个接口,但是在类定义时,继承的类必须写在最前面。

    2.泛型方法中的泛型参数在方法被调用时确定。常见形参位置带有泛型,然后根据传入实参确定,不再详叙。还有一种少见的情况是根据引用类型来确定的,需要注意。

    public class Testing {
    //
    	public <T> T generic(){
            String s1 = "generic";
            return (T)s1;
        }
    	
    	@Test
        public void test2(){
            ReflectionTest r1 = new ReflectionTest();
            String s1 = r1.generic();
            Sort s2 = r1.generic();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这里强转成什么类型是由String s1或Sort s2决定的,此时才决定泛型类型。
    返回值本身是String类,所以第一次调用不报错,第二次调用报错。

    3.泛型通配符的读写情况

    首先声明,在以下用到list的代码中,将get方法称为读,将add方法称为写。

     @Test
        public void wildcard(){
            List<?> list = null;
            List<String> list1 = new ArrayList<>();
            list1.add("A");
    
            list = list1;
    //        read
            Object o = list.get(0);
            System.out.println("o = " + o);
    
    //        write
            list.add("B");//此处报错
            list.add(null);//添加null不报错
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    对于读的情况不难理解。
    对于写的情况。将通配符可以看作是一个范围,或者一个可列集合(特指数学概念,不是java中的接口)。List< Integer >显然在List集合中。

    List<Integer> list2 = new ArrayList<>();
    list = list2;
    
    • 1
    • 2

    是允许的,但这样list.add(“B”);就会报错。
    add方法中只能传递 集合List中的全体元素调用后不报错的参数。但此集合元素是无限的,显然无法做到。

    下面来看有上边界通配符的情况

    class Father{}
    // interface B{}
    class Son1 extends Father{}
    class Son2 extends Father{}
    
    • 1
    • 2
    • 3
    • 4
      @Test
        public void upperBounded(){
            List<? extends Father> list = null;
            List<Father> list1 = new ArrayList<>();
            list1.add(new Father());
            list = list1;
            
    //        read 没问题
            Father father = list.get(0);
    //        write 除了null,剩下的报错
            list.add(null);
            list.add(new Father());
            list.add(new Son1());
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这里可能对 list.add(new Father());list.add(new Son1());报错产生困惑。还是如上所述,只是范围,或者说一个有限的可列集合(此处单指数学概念,并非java接口),它包含了所有< Son1>< Son2>……只要是Father子类的泛型情况。List< Son2 >显然在List集合中。
    List< Son 2> list1 = new ArrayList<>();list = list1;是允许的,但这样 list.add(new Father());list.add(new Son1());就会报错。
    add方法中只能传递 集合中的全体元素调用后不报错的参数。

    下面来看下边界通配符的情况

     @Test
        public void lowerBounded(){
            List<? super Father> list;
            List<Father> list1 = new ArrayList<>();
            list1.add(new Father());
    
            list = list1;
    //        read
            Object object = list.get(0);
    
    //        write
            list.add(new Father());
            list.add(new Son1());
            list.add(new Son2());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    对于确定下边界的统配符来说,读写总是没问题的。读的情况不难理解。
    对于写的情况,根据上述的规则:add方法中只能传递 集合中的全体元素调用后不报错的参数,因为此处的全体元素都是Father的父类,写入自然没有问题。

  • 相关阅读:
    迁移评分模式的跨域学习资源推荐算法
    docker 开发环境搭建
    pdd.order.information.get拼多多订单详情接口代码对接教程
    基于goravel的CMS,企业官网通用golang后台管理系统
    vue v-for
    Unity 之 使用定时调用与Update 正常帧更新的运行答疑
    基于布朗运动的文本生成方法-LANGUAGE MODELING VIA STOCHASTIC PROCESSES
    java对象的内存布局
    Spring Boot 应用启动时 java.lang.reflect.InaccessibleObjectException 问题的解决
    Ribbon
  • 原文地址:https://blog.csdn.net/qq_43726119/article/details/133955832