Java:包装类&简单认识泛型

一、包装类

  包装类指的是基本数据类型(如int、double等)对应的类类型,我们可以通过包装类直接调用里面的方法!

基本数据类型                      包装类
byte                             Byte
short                            Short
int                              Integer
long                             Long 
float                            Float
double                           Double
char                             Character
boolean                          Boolean

除了Integer和Character,其余基本数据类型的包装类都是其对应基本数据类型的首字母大写! 



二、装箱和拆箱

1、装箱:把一个基本类型转为包装类型

 //装箱
public class Test1 {
    public static void main(String[] args) {
        int a=0;
        Integer ii=Integer.valueOf(a);//显示装箱
        Integer ii2=a;//自动装箱(底层调用的也是valueOf方法)
        
    }
}

2、拆箱:把一个包装类型转换为基本类型 

//拆箱
public class Test1 {
    public static void main(String[] args) {
       Integer ii=10;//自动装箱
        int a=ii.intValue();//手动拆箱
        int aa=ii;//自动拆箱(底层调用的也是intValue方法)
      

    }
}



一个问题:下面程序运行的结果是什么?

//程序运行的结果是什么?
public class Test1 {
    public static void main(String[] args) {
       Integer a=100;
       Integer b=100;
        System.out.println(a==b);//true or false

        Integer c=200;
        Integer d=200;
        System.out.println(c==d);//true or false

    }
}

按照一般的逻辑,这个程序的运行结果要么都为true,要么都为false,那我们来看看实际过程中的结果到底是什么?

为什么会出现这样的结果?

 让我们来分析一下这段代码:

 1、首先,Integer a=100涉及的是装箱操作!这是我们上面所学的,而且我们知道这个装箱属于自动装箱它的底层调用的是valueOf方法!

2、那么就需要进入Integer类中看看这个valueOf方法了!

如图:

这个方法是这样执行的,如果参数 i 的范围属于[IntegerCache.low,IntegerCache.high]之间,那么函数返回数组的一个元素!

否则新实例化一个Integer类!

问题的关键就在于这个范围:让我来告诉大家,这个范围就是  [-128,127],因此才会出现截然相反的结果!



三、什么是泛型

泛型:简单来说,就是适用于许多许多类型!从代码上讲,就是对类型实现了参数化,使类型变得像参数一样可以作为一个数组的元素!

如果听不懂看,也没有问题,这个描述有点过于抽象,让我们看看实例加深对这段话的理解!

举个例子:实现一个类,类中包含一个数组成员,使得数组可以存放任何类型的数据!也可以根据成员方法返回数组中的某个元素! 

因为Object是所有类的父类,任何子类都继承于Object类,因此使用Object类作为数组类型。

//实现MyArray类:这个类有一个数组成员myArray,可以存放任何类型的数据
class MyArray{
    //数组成员
    public Object[] myArray=new Object[10];

    //成员方法:可以给数组传入任何类型的参数(如int,double等)
    public void setValue(int pos,Object x){
        myArray[pos]=x;
    }

    //成员方法:可以获取数组中的元素
    public Object getValue(int pos){
        return myArray[pos];
    }
}


public class Test1 {
    public static void main(String[] args) {
    MyArray myArray=new MyArray();//实例化一个MyArray类
    myArray.setValue(1,12);//给myArray[1]存入int类型的1
    myArray.setValue(2,"hello");//给myArray[2]存入String类的"hello"
    }
}

  接下来我们进行一个操作,获取数组中的"hello",并将其赋值给String类的str。

如图:

这样做的化需要强制类型转换,因为你getValue返回值的类型是Object类,你将其返回值赋值给String类时就需要将Object类强制转换为String类

如图:强制类型转换后,程序不会报错!

   但是这里就有一个问题了,这个类只能接收任何类型的数据,但是每次取出数据的时候,我们都需要强制类型转换操作,才可以获取该数组元素!如果这个数组存储了许许多多的数据时,我们怎么知道要取出的元素是什么类型的呢?

答:这个时候,我们就需要对这个代码进行修改了,同时使用泛型语法!



泛型语法:

以下对代码的修改如下:

对类的修改:

1、在MyArray类的后面添加<T>:   这个T表示这个类是一个泛型 

2、setValue方法的传入参数的数据类型修改为T

3、getValue方法的返回值类型改为T,同时进行强制类型转换!

使用该泛型类时的语句修改:

1、实例化该泛型类时,在类名后面添加<类型名>,这个类型名取决于你即将传入的数据类型,比如,你要传入int类型的数据,就填Integer,如果要传入字符串,就填写String

//对类的修改
class MyArray<T>{        //1、<T>:表示这是一个泛型类
    public Object[] myArray=new Object[10];
    public void setValue(int pos,T x){     //2、参数传入类型给为T
        myArray[pos]=x;
    }

    public T getValue(int pos){//3、方法的返回值类型改为T
        return (T)myArray[pos];//返回值强制类型转换为T
    }
}


//使用该泛型类时的语句修改
public class Test1 {
    public static void main(String[] args) {
    MyArray<Integer> myArray=new MyArray<Integer>();//1、<>里面填写类型名
    myArray.setValue(1,12);
    //此时无法给数组传入String类的数据,因为实例化MyArray时,指定了当前类型为整型
    myArray.setValue(2,"hello");//!!!这一句报错!


    }
}



  这里要强调的是,看到上面代码我注释的报错语句没?如图:

此时无法给该数组出传入字符串,因为在前面实例化的时候指定了当前类型为int

它的具体原理如图:

这里解释一下我们要给数组传入的类型是int类型,为什么<>不填写int ,而是Integer,这是因为此时的<>只能填写类型名,不能填写基本数据类型(int、double之类)!因此得使用其基本类型的包装类代替!

注意:实例化的时候:以下为例:

MyArray<Integer> myarray=new MyArray<Integer>();

也可简写为:

MyArray<Integer> myarray=new MyArray<>();

使用了泛型之后,当每次取出数据时,就不需要我们进行强制类型转换! 



 如图:  类名<T> 表示一个占位符,表示当前类是一个泛型类(并不是一定要填T)

了解:【规范】类型形参一般使用一个大写字母表示,常用的名称有:

E:表示Element
K:表示Key
V:表示Value
N:表示Number
T:表示Type


四、泛型的上界

在定义泛型类的时候,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束!

语法:
class 泛型类名称<类型形参 extends 类型边界>{
//.......
}

 举一个例子:


//它表示以后给MyArray传入的参数,要么是Number这个类,要么是Number的子类
class MyArray<E extends Number>{
//...
}


MyArray<Integer>;//正常运行,因为Integer是Number的子类型
MyArray<String>;//编译错误,因为String不是Numberd的子类型


举另外一个相对复杂的例子:

//它表示E必须是实现了Comparable接口的
class MyArray<E extends Comparable<E>>{
//...
}

实例:实现一个泛型类,可以找出数组中的最大值

//定义一个泛型类,找到数组当中的最大值:

//这样做是为了限定边界,T一定是实现了Comparable接口的
class Alg<T extends Comparable<T>>{
    public T findMax(T[] array){
        T max=array[0];
        for(int i=0;i< array.length;i++){
            //此时的max是一个引用类型,引用类型之间无法直接比较,所以要使用compareTo方法
            if(array[i].compareTo(max)>0){
                max=array[i];
            }
        }
        return max;
    }

}

 接着就可以根据需要,求出任意类型数组中的最大值:

public static void main(String[] args) {
        //比较Integer类型数组
        Alg<Integer> alg=new Alg<>();
        Integer[]  array={1,2,3,4};
        Integer num=alg.findMax(array);
        System.out.println(num);

        //比较字符串数组
        Alg<String> alg1=new Alg<>();
        String[] array1={"abc","bcd","def"};
        String str=alg1.findMax(array1);
        System.out.println(str);

    }

运行结果:



五、泛型方法

泛型方法:顾名思义,就是适用于任何类的方法!

那么该如何写一个泛型类呢?


//泛型方法格式:
方法限定符 <类型形参列表> 返回值类型 方法名称 (形参列表){}
class Alg2{
    //写一个泛型方法:找出数组中的最大值(任何类型的数组都适用)
    public <T extends Comparable<T>> T findMax(T[] array){
        T max =array[0];
        for (int i = 0; i < array.length; i++) {

            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}

 使用泛型方法找出数组中最大值:

public static void main(String[] args) {
        //比较Integer类型的数组
        Alg2 alg2=new Alg2();
        Integer[] array={1,2,4,5};
        Integer max=alg2.findMax(array);//注意!
        System.out.println(max);

        //比较String类型的数组
        String[] array1={"abc","bcd","def"};
        String str =alg2.findMax(array1);
        System.out.println(str);

    }

有些伙伴可能会疑问,前面教学泛型类的时候,好歹在实例化泛型类的时候使用<>传入了类型名称如 Alg<Integer> alg=new Alg<Integer>();)这样起码可以知道是你的T表示什么类型,但是使用泛型方法时却没有使用<>中传入类型名称。这是为什么?

答:其实是因为,上述代码语句:Integer max=alg2.findMax(array)已经可以推出T是Integer类型了。它类似于实例化泛型类时的语句:MyArray<Integer>   myarray=new MyArray<>();

如果非要传入类型的话,也可以写成Integer max=alg2.<Integer>findMax(array)

程序运行:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值