包装类与泛型

包装类

初步理解

  • 之前所接触的类型,比如整型int,浮点型double,字符char,这些是基本数据类型,但是他没法含有某些功能。比如C++中的vector就是静态数组的进阶,通过“.”的操作就能实现排序插入等功能。这就是面向对象的特性,包装类就是基本数据类型的进阶版本,可以直接实现很多的功能。
    在这里插入图片描述

装箱和拆箱

装箱,就是把普通的基本数据类型“放到”更“高级”的包装类当中。
拆箱。把“高级”的包装类转换成对应的基本数据类型

    public static void main(String[] args) {
        int a=10;;
        Integer i=a;//装箱操作
        System.out.println(i);

        Integer i2=Integer.valueOf(a);//拆箱操作(手动拆箱)
        System.out.println(i2);
    }

拆箱——手动拆箱&自动拆箱

    public static void main(String[] args) {
        Integer a=10;
        int b1=a;//(自动拆箱)
        int b2=Integer.valueOf(a);//拆箱操作(手动拆箱)
    }

思考问题

public static void main(String[] args) {
	Integer a = 127;
	Integer b = 127;
	Integer c = 128;
	Integer d = 128;
	System.out.println(a == b);//true
	System.out.println(c == d);//false
}
  • 运行上面的代码,有个true一个false,为什么?从哪个角度去思考?
    • 上面就进行了一种操作——装箱 ,自动装箱也会使用手动装箱的valueOf,所以查看一下valueOf的源码:
      在这里插入图片描述
  • 从借出来的源码片段来看,当传入的整数值大于一个值和小于另一个值的时候才会返回装箱后的类型,否则就会new一个新的对象。
  • 通过查看在这里插入图片描述
  • 可以看出,在-128~127之间的数组才会返回包装类,其余的都会新建一个对象,上面代码的输出结果也就解决了

泛型类

理解

  • ⼀般的类和⽅法,只能使⽤具体的类型: 要么是基本类型,要么是⾃定义的类。如果要编写可以应⽤于
    多种类型的代码
    ,这种刻板的限制对代码的束缚就会很⼤。----- 来源《Java编程思想》对泛型的介绍
  • 通俗讲,泛型:就是适⽤于许多许多类型。从代码上讲,就是对类型实现了参数化。

实现方式对比

  • 现在实现⼀个类,类中包含⼀个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员⽅法返
    回数组中某个下标的值?
    • 思路:
      1. 我们以前学过的数组,只能存放指定类型的元素,例如:int[] array = new int[10]; String[] strs =
        new String[10];
      2. 所有类的⽗类,默认为Object类。数组是否可以创建为Object?
class MyArray {
	public Object[] array = new Object[10];
	public Object getPos(int pos) {
		return this.array[pos];
	}
	public void setVal(int pos,Object val) {
		this.array[pos] = val;
	}
	}
	public class TestDemo {
	public static void main(String[] args) {
		MyArray myArray = new MyArray();
		myArray.setVal(0,10);
		myArray.setVal(1,"hello");//字符串也可以存放
		String ret = myArray.getPos(1);//编译报错
		System.out.println(ret);
}
}

问题:以上代码实现后 发现

  1. 任何类型数据都可以存放
  2. 1号下标本⾝就是字符串,但是确编译报错。必须进⾏强制类型转换
    虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有
    ⼀种数据类型。⽽不是同时持有这么多类型。所以,泛型的主要⽬的:就是指定当前的容器,要持有
    什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传⼊
    什么类型。
class MyArray<T> {
    public Object[] array = new Object[10];
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
    public T getPos(int pos) {
        return (T)this.array[pos];
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();//1
        myArray.setVal(0,10);
        myArray.setVal(1,12);
        int ret = myArray.getPos(1);//2
        System.out.println(ret);
        myArray.setVal(2,"bit");//3
    }
}
  • 表示占位符,表示当前是一个泛型类,T没有明确含义,换成任何一个字母都可以
  • 泛型类<类型实参> 变量名; // 定义⼀个泛型类引⽤
    = new 泛型类<类型实参>(构造⽅法实参); // 实例化⼀个泛型类对象

泛型的编译过程

在这里插入图片描述

泛型方法

类有泛型,方法也可以有泛型

对比写法

//泛型方法
class Alg3 {
    public static <T extends Comparable<T>> T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}
public static void main(String[] args) {//静态方法不用通过类来调用
        Integer[] array = {1, 3, 21, 15, 8, 17, 6, 9};
        int ret=Alg3.findMax(array);
        System.out.println(ret);
    }
class Alg<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}
    public static void main(String[] args) {
        Alg<Integer> alg1 = new Alg<Integer>();
        Integer[] array = {1, 3, 21, 15, 8, 17, 6, 9};
        int ret = alg1.findMax(array);
        System.out.println(ret);
        Alg<String> alg2 = new Alg<String>();

    }
区别
  1. 泛型方法不需要在声明生成新的类的时候说明,泛型类需要在生命新类的时候声明类型
  2. 泛型方法只对一个类中的单个方法起作用,一般式静态的,不需要通过类来调用;泛型类是对整个类都起作用

泛型的上界

public class MyArray<E extends Number> {
...
}

只接受 Number 的⼦类型作为 E 的类型实参

MyArray<Integer> l1; // 正常,因为 Integer 是 Number 的⼦类型
MyArray<String> l2; // 编译错误,因为 String 不是 Number 的⼦类型

通配符

在这里插入图片描述

package 泛型;

class Message<T> {
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
}

public class 通配符 {
    public static void fun(Message<String> temp){
        System.out.println(temp.getMessage());
    }

    public static void main(String[] args) {
        Message<String> message = new Message<String>() ;
        message.setMessage("hello");
        fun(message);
    }
}

通配符上界

<? extends 上界>
<? extends Number>//可以传⼊的实参类型是Number或者Number的⼦类
class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}
class Plate<T> { // 设置泛型
private T data ;
	public T getData() {
	return data;
}
public void setData(T data) {
	this.data = data;
}
}
public class TestDemo {
public static void main(String[] args) {
	Plate<Apple> plate = new Plate<>() ;
	plate.setData(new Apple());
	fun(plate);
	Plate<Banana> plate2 = new Plate<>() ;
	plate2.setData(new Banana());
	fun(plate2);
}
// 此时使⽤通配符"?"描述的是它可以接收任意类型,但是需要是Fruit或者Fruit的⼦类
public static void fun(Plate<? extends Fruit> temp){
	//temp.setData(new Banana()); //error
	//temp.setData(new Apple()); //error
	System.out.println(temp.getData());
}
}
  • 先说明一个可能有疑问的点
    plate2.setData(new Banana());这种写法set方法传入一个类好像之前没有写过。之前传递的都是一些基本数据类型,这里传递的是类。我们原来在main方法中new一个新对象,这里new出新对象的位置变到了类的里面。
    pa.setData(new Banana())和
    Fruit food = new Fruit();
    Fruit fruit=(Fruit) food;的实现含义是一致的。

通配符的下界(代码见上)

在这里插入图片描述

posted @ 2025-07-19 22:04  dearbi  阅读(0)  评论(0)    收藏  举报  来源