包装类和泛型

目录

包装类

泛型

泛型方法

泛型接口

通配符

类型擦除


包装类

包装类就是把8大基本类型封装到类之中。
 

有两个原因。

原因一:

我们之前说过:Object类可以接收所有引用数据类型(数组,类,接口),现在就剩下基本类型了

所以为了让Object类可以接收Java中一切内容,引入包装类,把基本类型的数值封装到类的对象之中就产生了包装类

原因二:

基本类型的默认值有时候挺烦人的,它的默认值在很多场景下会造成误导。

比如int整形数组的时候,它就默认值就是 0。那么如果我保存的就是 0 呢?这怎么区分是默认值还是你保存的值

但如果是类的话,引用类型的默认值是 null,我们就可以清楚的判断是否为空了。

基于以上两个原因,于是有了包装类的产生。

JKD的包装类有以下8种

数值型包装类(Number的子类)

除了int和char的包装类有点特殊,其他包装类都是首字母大写。 

基本类型转换成包装类:以整形为例

用构造方法把基本类型转换成包装类 

 

可能会觉的这样装箱,拆卸的太麻烦了。

所以Java里面提供了——自动拆装箱 

这是原来的步骤:

 优化后: Integer 和 10这个整形字面量是两个类型,原本是不可以这样的,但现在Java内容自动帮你进行了装箱的操作,让你可以直接进行赋值。

 在运算的时候本来是要先进行拆箱的,但现在我们也可以直接进行运算了,因为内部自动帮你进行了拆箱过程。

有了自动拆装箱,使用包装类就和使用基本类型完全一致。

唯一需要注意一下的就是把平时写的int 换成 Integer,char换成Character 之类的。
 

看看编译之后的字节码

在编译之后就是我们平常使用的那样,这算是Java的语法糖,就是为了方便程序员使用方便而设计的。

总结:默认值不同,比较用equals方法

 案例:一个比较的是地址,一个比较的是内容值。

 思考题:下面代码输出的结果是什么?

 运行结果:

 怎么会这样?不是说 == 比较的是地址吗,难不成他们那样的地址又相等了?确实是!

解析:这里还是涉及到了我们学字符串的常量池这个概念。

 当第一次出现120时,Integer对象保存到常量池中。

 第二次出现120时,因为此时常量池存在了i2就直接复用了这个对象。

如果超到了这个范围就不会保存了。

 其实不止Integer,其他的包装类都有常量池这个概念。可能你会觉得的这么多,这怎么去分辨去记忆啊?不需要!

不需要记这些规则,你只需要知道只要是引用类型的比较都—律使用equals方法咋样都不会错!!!

小知识:阿里编码规范:所有POJO(普通)类的成员变量—律使用包装类替代基本类型

泛型

定义泛型对象时,只能使用类
基本类型不能保存到泛型中,必须使用包装类

 

 我们发现上面x的取值类型都是不一致,而Java强类型语言,在定义x和y的时候必须强制定义变量类型

那么此时x,y应该取啥类型好呢?

x和y的取值飘忽不定,但发现我们之前学的Object不是刚好可以接受任意类型吗?

示例代码:

public class Point {
    private Object x;
    private Object y;

    public void setX(Object x) {
        this.x = x;
    }

    public void setY(Object y) {
        this.y = y;
    }

    public Object getX() {
        return x;
    }

    public Object getY() {
        return y;
    }

    public static void main(String[] args) {

        Point point1 = new Point();
        point1.setX(10);//给成员变量赋值
        point1.setY(20);//给成员变量赋值
        int x = (int) point1.getX();//因为是Object类型,所以需要强转
        int y = (int) point1.getY();//因为是Object类型,所以需要强转
        System.out.println("x = " + x + ", y = " + y);

    }
}

运行结果:正常赋值。 

现在换一个输出类型,比如是字符串。

        Point point1 = new Point();
        // 要求此时x和y必须是相同类型的,设置是由用户设置的
        point1.setX("东经20度");
        point1.setY("北纬30度");
        String x = (String) point1.getX();
        String y = (String) point1.getY();
        System.out.println("x = " + x + ", y = " + y);

也是正常接受输出了。 

但这里存在一个风险!这个输入类型是由用户来输入的

当用户不小心输入的x和y是不同类型时,编译是没问题的,但是在下面取出x和y的值时,强制类型转换就会报错,运行时异常。

编写代码时没有输出报错,但此时X是int类型,把它强转成String类型,肯定是会报错的。 

—般来说,我们要求把所有的错误都提前暴露在编译阶段,程序还没跑起来就能发现错误
 

那怎么去解决这样的问题呢?泛型就的产生。

引入泛型——守门员,编译阶段检查类型是否—致的手段。

所谓的泛型指的是在类定义时不明确类型,在使用时明确类型

定义泛型使用 "< >" 操作符

在类的声明这块加上一个 < >,里面是类型参数 。此时MyPoint类就是一个泛型类

 

例如在定义成员变量时:不确定是啥类型。

 

这样就定义了一个泛型类。

使用泛型类 

如果代码这样写表示什么意思:

 表示此时 T 就是String类。

 

举例:使用里面的方法的时候

 这样这个类的类型就由我们随意的定义了。而且当我们定义是String类时,输入的却是整形,这时编译器就会直接报错了。

 而且此时在获此值的时候也不需要我们强制类型转换了。

 整体运行结果:一样能完成我们的目的

我们发现,引入泛型后,可以在编译阶段检查设置的类型值是否是指定类型,若不一致,编译报错取出值的时候,就无须再进行强转——这就是泛型最大的好处。
 

 我们就可以使用泛型来改造我们动态数组和链表
之前保存的只能是int,当有泛型以后,我们可以保存任意类型。

如果我们此时就想x,y是不同的类型呢?

若泛型类中存在多个类型参数,成员变量的类型不—定一致。(多个类型情况用逗号分隔)

 使用不同的大写字母指代不同类型。

此时产生对象时,T和E的类型可以相同也可以不同。

不相同情况:

 相同情况:

泛型方法

泛型除了可以用在类声明上,也可以单独来定义方法。

注释:一个类是普通类仍然也可以定义泛型方法

 

在泛型类:

 普通的方法,在对象产生的时候,类型就已经被定义了,就是跟泛型类的类型一致。

而泛型方法,却可以根据自己输入的任意值而变化。

 因为我想输入整形,所以用Integer来接收。

 泛型方法始终以自己的类型参数为准,与泛型类中的T无关。

 但是这里推荐茬泛型类中存在了泛型方法,定义为不同的类型参数,不造成异议。

 虽然同名称不影响泛型方法,但容易造成误解,所以这里最后修改为不同的名称。

 注释:泛型方法,你传入是数据是什么类型,它就会自动的转换为对应的类型。

 注释:到底应该方法算不算泛型方法,就看有没有 < > 操作符

泛型接口

泛型还可以声明在接口中,一旦一个接口使用泛型声明,子类在实现接口时就有两种选择

a. 继续保留泛型

 b.子类明确当前类型

案例:

Messagelmpl1子类仍然是泛型类,因此产生的啥类型,就可以接收啥类型

 

通配符

比如我想创建一个接受 IMessage 类型的方法

 定义方法时,这样写是错误的,因为是类型参数,必须要明确类型。

 比如String类型

 有泛型以后出现的问题:

 有泛型之后,使用泛型类或者接口对象方法的参数不好定义

 fun只能接收String类型的IMeesage对象
 就是说我想使用你这个泛型类作为传参类型,但在自己类里面创建方法时,参数类型就不好定义了。

如果想解决,重载可以解决吗?就是每一个不同类就重载一个不同类型参数的方法。不可以,搞的太复杂了。

所以有了 通配符 的概念。

1.  问号通配符,只能定义在方法中,表示可以接收所有类型的泛型类

注释: 只能调用getter类的方法,无法设置具体值

使用方法: 

提问:能否在fun方法中调用set类的方法修改值?

 答:只能调用get方法,而不是调用set方法。

此时定义fun方法时根本都不知道会传入什么类型的msg对象你咋设置值呢?

举例: 编译器都说了,现在是个 ? 你咋能设置String类型呢


第二种

2. ? extends 类 : 设置泛型上限 

可以用在类和方法的声明上

 传入的类型:只能是Fruit包括Fruit的子类

 注释:  Number类型包括了八大基本类型,Integer,Double..等等都是它的子类,继承了。

 注释: 明确了当前泛型类的天花板,父类。

提问:现在能否调用set方法设置值?

答:还是不能调用。

我现在明确知道的是父类是啥,现在Number设置也只能设置Number的值
由于不知道传入的子类是啥
父类的Number类型的值强制赋值给子类:向下转型~~不—定成功。

比如我设置成 10,是 Number,但如果传入的是 10.3double类型呢?它也是Number的子类,所以就不行了。

不同的子类之间的类型没有任何关系,不能设置值

也可以让这个类 继承 Number ,这样在使用这个类产生的对象就不能有String类了

 上限通配符两点说明:

1.可以定义在方法参数和类中,明确此时泛型的上限为某个具体的类
 

⒉设置的父类,不同的子类之间没有直接关系,因此仍然无法设置某个具体值
 

第三种:

3.  < ? super 类 >  规定泛型下限——地板

举例:

 此时不能接受msg2类型,因为此时msg2是Integer类型,不是String的父类。

注释:可以把 问号换成 Integer来看: Integer super String

 相当于:整形是字符串的父类吗?明显不是

提问:此时set能否修改值?

答:可以。 此时明确知道的是子类,不管 ? 是啥类型,都一定是String的父类
设置一个String对象,天然都is a父类——向上转型


因为不管你输入的是什么,都一定是String或者其子类。

规则:

 a.由于此时明确的是下限,明确的是子类是谁,由于子类天然是父类可以设置值

b.super下限通配符只能用在方法内部,不能在类中定义。
 

---------------------------------------------------------------------------------------------------------------------------------

类型擦除

举例:  进入JVM之后都是Object类型,一样的

 

 举例2:

注释:泛型只存在编译阶段

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值