我对java <? extends T>和<? super T>的理解

最近写项目用到了<? extends T>和<? super T>,于是我搜了一下他俩的相关解释,看到了这文章java <? extends T>和<? super T>介绍,写的挺好的,最后发现其他文章都是类似的内容,猜想应该是某教程的笔记。

我在这里对这篇文章进行简单总结以及我写一下对java <? extends T>和<? super T>的理解。

 

总结 

<? extends T><? super T>Java泛型中的“通配符(Wildcards)”和“边界(Bounds)”的概念。 

  • <? extends T>:是指 “上界通配符 ”,能接收T类及他的子类
  • <? super T>:是指 “下界通配符 ”,能接收T类及他的父类

上界<? extends T>不能往里存,只能往外取

(1)<? extends Fruit>会使往盘子里放东西的set( )方法失效,但取东西get( )方法还有效

(2)取出来的东西只能存放在Fruit或它的基类里面,向上造型。

 

下界<? super T>不影响往里存,但往外取只能放在Object对象里

  (1).使用下界<? super Fruit>会使从盘子里取东西的get( )方法部分失效,只能存放到Object对象里。

因为规定的下界,对于上界并不清楚,所以只能放到最根本的基类Object中

  (2).set( )方法正常。

 

 我的总结和理解

 我们先来了解一下等号赋值。

 比如定义一个变量:int a = 1;

 其实就是a变量分配了4个字节来存放数字1,如果等号右边的数字比4个字节大,他就会内存溢出报错。

我们可以想象一下:等号右边是我们想要装多少水,等号左边是用多大的容器装 

其实这类一个值赋给另一个值报错,基本就是底层内存分配不足的问题了。

 

 引用上面文章的水果盘盛水果的例子。

public static void main(String[] args) {
//        Plate<Apple> p=new Plate<Apple>(new Apple());
        Plate<? extends Fruit> p=new Plate<Apple>(new Apple());
        Plate<? super Fruit> p1=new Plate<Food>(new Food());
    }


    static class Plate<T>{
        private T item;
        public Plate(T t){item=t;}
        public void set(T t){item=t;}
        public T get(){return item;}

    }

    //Lev 1
    static class Food{}

    //Lev 2
    static class Fruit extends Food{}
    static class Meat extends Food{}

    //Lev 3
    static class Apple extends Fruit{}
    static class Banana extends Fruit{}
    static class Pork extends Meat{}
    static class Beef extends Meat{}

    //Lev 4
    static class RedApple extends Apple{}
    static class GreenApple extends Apple{}

 为啥会出现<? extends T>和<? super T>?

 定义一个“水果盘”,逻辑上水果盘当然可以装苹果。结果是报错。

Plate<Fruit> p=new Plate<Apple>(new Apple());

为啥会报错?

因为他编译过后是看不到泛型的(泛型擦除)

比如一个泛型成员变量private <T> t;  ,给泛型赋值Apple,他编译后就是private Apple t;,他是看不到泛型的。

你等号右边泛型为Apple ,右边泛型却不是Apple,鬼知道你那分配的内存够不够装下呀,也懒得给你判断了,就干脆给你报错了。

 

解决方案是使用 <? extends T>和<? super T>。

Plate<? extends Fruit> p=new Plate<Apple>(new Apple());

为啥使用 <? extends T>和<? super T>能解决上述问题?

 java为解决这个问题直接定义规则,使用<? extends Fruit>,所有是Fruit的子类我都能容得下,不是Fruit的子类的在java层直接报错,省得你到底层报内存溢出错误。

他在java层处理后就变成这样了

Plate<Fruit> p=new Plate<Apple>(new Apple());

 虽然我们这样编写会报错,但事实上它是可以这样分配内存的(这不就是多态吗),这里也就解释了为啥(<? extends T>不能往里存,只能往外取<只能放在Fruit对象或者他的父类中>

 


Plate<? super Fruit> p1=new Plate<Food>(new Food());

 同理使用<? super Fruit>,所有是Fruit的父类我都能容得下,不是Fruit的父类的在java层直接报错

 他在java层处理后就变成这样了

Plate<Object> p=new Plate<Food>(new Food());

Object是你所有类它爸, 它当然有资格接收你的赋的值了。这里也就解释了为啥(<? super T>不影响往里存,但往外取只能放在Object对象里

 

额外知识:

public static void main(String[] args) {
        A a = new A1();
        System.out.println(a.a);
        System.out.println(a.a1);
        System.out.println(a.show);
    }

    public static class A{
        int a = 1;
    }

    public static class A1 extends A{
        String a1 = "a1";
        public void show(){
            System.out.println(a1);
        }
    }

 为啥多态中只能调用父类中的变量和方法?

你想想子类本就是父类的扩展,理应比父类需要更多的内存存储,为啥父类的指针可以指向子类?所以在多态中父类指针只能指向子类继承父类哪些数据,而子类扩展的数据它没有分配内存(有心无力)。参考https://blog.csdn.net/ljlinjiu/article/details/83745483

 

 以上全是我的猜想,只供参考(手动滑稽)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值