泛型中extends和super的区别

100 阅读3分钟

1、java泛型实现了,在不清楚将要传入什么类型的对象是可以使用泛型的方式进行传值.

“上界”与“下界” 如果 < E extends Number> 说明E 最多被擦除为Nubmer类,E可能包含的元素类型是Number及其子类。 Number就是E的上界。所以我们可以调用Number的方法。 而< E super Number>则说明E 最少被擦出为Number类,E可能是Number类或者它的父类。

  • extends 上界

      //这里的E是一个泛型,这里对泛型做了限制只能是Number类的子类 ,这里是第一次对类型进行限制
      class NList<E extends  Number>{
          public void add(E e){
          }
      }
      public class Test {
          public static void Main(String[] args){
              //这里是第二次的限制,限制了list的类型只能是BigDecimal类型的
              NList<BigDecimal> nList = new NList();
              //这一行代码是报错的,因为String不是Number所以不能新建list
              NList<String> n2List = new NList();
              nList.add(new BigDecimal(1));
              //这一行也是报错的,因为上面的list的类型声明的是BigDecimal类型
              nList.add(1);
          }
      }
    
  • super 下界

         class Aa{
         }
         class Bb extends Aa{
         }
         class Cc extends Bb{
         }
         class NList{
             public void add(ArrayList<? super Bb> list){
             }
         }
         public class Test {
             public static void main(String[] args){
                 ArrayList<Bb> BbList= new ArrayList<Bb>();
                 new NList().add(BbList);
                 ArrayList<Aa> AaList= new ArrayList<Aa>();
                 new NList().add(AaList);
                 ArrayList<Cc> CcList= new ArrayList<Cc>();
                 //这里报错了,因为这个add方法限制了传入的类型应该是Bb的父类或者是自己,不能是Bb的子类
                 new NList().add(CcList);
                 //这里标注一下如果使用了多态会怎么样
                 Bb b = new Cc();
                 AaList.add(b);
                 //class com.ruoyi.web.Cc
                 System.out.println(b.getClass());
                 //其实这里还是放进去了,通过多态的办法
                 new NList().add(AaList);
             }
         }
    
  • 边界问题带来的get set的问题

    确定上边界,不能使用Set方法
    确定下边界,不能使用get方法 , 但是最后实验发现是可以使用的,可能是jdk版本的问题吧
    //定义一个盘子的类
    class plate<T>{
        private T t;
        public plate(T t){
            this.t = t;
        }
        public  void set(T t){//测试1
            this.t = t;
        }
        public T get(){
            return t;
        }
    }
    class Food{}//食物
    class Furit extends Food{}//属于食物的水果
    class Apple extends Furit{}//属于水果的苹果
    class Banana extends Furit{}//属于水果的香蕉
    class Aaaa{
        public void test(){
            plate<? extends Furit> p10 = new plate<Apple>(new Apple());
    
            p10.get();
            //因为 plate<? extends Furit> p10 = new plate<Furit>(new Apple()); 左面限制了数据类型是Furit或者子类就行了
            //倘若可以使用set(new Banana()),由于Banana也是Furit子类,编译器无法判断错误,但运行则会出错
            //因此编译器直接取消了上边界extends中的set方法
    //        p10.set(new Banana());
    
            //从结构出发,左边部分plate<? super Furit> p12:决定了p12只能接受Furit及其父类Food
            //编译看左,运行看右:假设get()方法可以使用,那么get的返回值用什么接收呢?
            //Furit getback = p12.get();运行时不一定正确
            //Food getback = p12.get();运行时也不一定正确
            //只有超类Object getback = p12.get();才能一定不报错
            //因此继续假设get返回值用Object存储
            //但是这样就使用不了除Object以外的任何方法,并且本身还很容易出错
            //因此编译器直接取消了下边界super中的get方法
            plate<? super Furit> p12 = new plate<Food>(new Apple());
            //实际情况发现并没有被取消
            p12.get();
            p12.set(new Banana());
        }
    }
    public class Test
    {
    
        public static void main(String[] args)
        {
        new Aaaa().test();
        }
    }
    
- 总节
> 为什么要使用泛型?<br/>
    原因:<br/>
        1、解决元素数据的安全性问题<br/>
        2、解决获取元素时,需要类型强转的问题<br/>