Java SE 学习笔记(八)—— 包装类与泛型

1 包装类


引言

  • 什么是包装类?
    • 包装类其实就是8种基本数据类型对应的引用类型
  • 为什么要提供包装类?
    • Java为了实现一切皆对象,为8种基本类型提供了对应的引用类型
    • 后面的集合和泛型其实也只能支持包装类,不支持基本类型

1.1 基本类型包装类


基本类型包装类的作用:将基本数据类型封装成对象 的好处在于可以在对象中定义更多的功能方法操作该数据

常用的操作之一:用于基本数据类型与字符串之间的转换

基本数据类型对应的包装类:

在这里插入图片描述

1.2 包装类的特有功能


1️⃣ 可以把基本类型的数据转成字符串类型(用处不大😕 )

在这里插入图片描述

🙋举个栗子:

public class Demo {
    public static void main(String[] args) {
//        可以把基本类型的数据转成字符串类型(没啥用)
        Integer a=23;
        String rs=a.toString();
        System.out.println(rs+666); // 23666

        String rs1=Integer.toString(a);
        System.out.println(rs1+666); // 23666

        // 可以直接+字符串变字符串
        String s = a + "666";
        System.out.println(s); // 23666
    }
}

2️⃣ 可以把字符串类型的数值转成真实的数据类型(真的很有用😋)

在这里插入图片描述

🙋举个栗子:

public class Demo {
    public static void main(String[] args) {
        
        // 使用valueOf创建包装类对象的两种方式
        Integer i1 = Integer.valueOf(200);
        Integer i2 = Integer.valueOf("200");
        System.out.println(i1); // 200
        System.out.println(i2); // 200

        String a="23";
        // 将字符串转成整数的两种方式:parseXxx、valueOf
//        int i = Integer.parseInt(a);
        Integer i = Integer.valueOf(a);
        System.out.println(i+1); // 24

        String b = "99.9";
//        double v = Double.parseDouble(b);
        Double v = Double.valueOf(b);
        System.out.println(v+1); // 100.9
    }
}

1.3 自动装箱 / 拆箱


  • 自动装箱:把基本数据类型转换为对应的包装类类型,基本类型的数据和变量可以直接赋值给包装类型的变量
  • 自动拆箱:把包装类类型转换为对应的基本数据类型,包装类型的数据和变量可以直接赋值给基本类型的变量

🙋举个栗子:

public static void main(String[] args) {
	// 更为简单地获取Integer的方式
	Integer i1 = 100;
	//   对象      = 默认是一个基本数据类型
	
	//jdk1.5的特性 --- 自动装箱
	
	//装箱: 把一个基本数据类型 变量对应的包装类.
	//自动: Java底层会帮我们自动的调用valueOf方法.
	System.out.println(i1);
	
	//jdk1.5的特性 --- 自动拆箱
	//拆箱: 把一个包装类型 变成对应的基本数据类型
	int i2 = i1;
	System.out.println(i2);
	
	Integer i3 = 100; //自动装箱机制
	i3 += 200;//i3 = i3 + 200;
	           //会把i3这个对象变成基本数据类型100.
	            //100 + 200 = 300
	        //把基本数据类型300再次自动装箱变成Integer对象赋值给i3
	System.out.println(i3);
	
	
	//细节:null可赋值给引用类型,但是不可以赋给基本类型
	// int a=null; // 报错
	Integer i4 = null;
	if(i4 != null){
	    i4 += 200;
	    System.out.println(i4);
}

❗️注意:

  • 包装类的变量默认值可以是 null
  • 在使用包装类类型的时候,如果做操作,最好先判断是否为 null,推荐的是,只要是对象在使用前就必须进行不为 null 的判断

练习:字符串中数据的处理

//需求:有一个字符串:“91 27 46 38 50”,把其中的每一个数存到int类型的数组中
//步骤:
//定义一个字符串
//把字符串中的数字数据存储到一个int类型的数组中
//遍历数组输出结果
public static void main(String[] args) {
    String s = "91 27 46 38 50";
    //获取字符串中的每一个数字.
    String[] strArr = s.split(" ");

    //创建一个int类型的数组.
    int [] numberArr = new int[strArr.length];

    //把strArr中的数据进行类型转换并存入到int数组中
    for (int i = 0; i < strArr.length; i++) {
        int number = Integer.parseInt(strArr[i]);
        numberArr[i] = number;
    }
    //遍历int类型的数组
    for (int i = 0; i < numberArr.length; i++) {
        System.out.println(numberArr[i]);
    }
}

2 泛型

2.1 泛型概述


不写泛型的弊端

public static void main(String[] args) {
	ArrayList list = new ArrayList();
	list.add("aaa");
	list.add("bbb");
	list.add("ccc");
	list.add(123);

	Iterator it = list.iterator();
	while(it.hasNext()){
		String next = (String) it.next(); // 强制类型转换
		int len = next.length();
		System.out.println(len);
	}
}

引入泛型,泛型是 JDK5 中引入的特性,它提供了编译时类型安全检测机制

  • 泛型的好处
    • 统一 数据类型
    • 把运行时期的问题提前到了编译期间
    • 避免了强制类型转换
  • 泛型的定义格式
    • <类型>:指定一种类型的格式,尖括号里面可以任意书写,一般只写一个字母。例如:<E><T>(不知道什么类型)
    • <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。例如: <E,T><K,V>

集合体系的全部接口和实现类都是支持泛型的使用的。

泛型可以使用的地方:

  • 类后面 —— 泛型类
  • 方法申明上 —— 泛型方法
  • 接口后面 —— 泛型接口

我们也可以自定义泛型

2.2 自定义泛型类


如果一个类的后面有 <E> ,表示这个类是一个泛型类,即定义类的同时定义了泛型的类

创建泛型类对象时,必须要给这个泛型确定具体的数据类型。

泛型类格式:

修饰符 class 类名<类型> {  }

范例:

public class Test<T>{}

此处的 T 可以随便写为任意标识,常见的如TEKV 等形式的参数用于表示泛型

🙋举个栗子:

需求:模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计

import java.util.ArrayList;

public class MyArrayList<E> {
    private ArrayList list=new ArrayList();

    public void add(E e){
    list.add(e);
    }
    public void remove(E e){
    list.remove(e);
    }

    @Override
    public String toString() {
        return list.toString();
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        MyArrayList<String> list=new MyArrayList<>();
        list.add("111");
        list.add("222");
        list.add("333");
        list.remove("222");
        System.out.println(list); // [111, 333]

        MyArrayList<Integer> list2=new MyArrayList<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.remove(1);
        System.out.println(list2);// [2, 3]
    }
}

泛型类的原理:

  • 把出现泛型类变量的地方全部替换成传输的真实数据类型

2.3 自定义泛型方法


定义方法的同时定义了泛型的方法就是泛型方法,其作用是,方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性

定义泛型方法格式:

修饰符 <类型> 返回值类型 方法名(类型 变量名) {  }

范例:

public <T> void show(T t){}

🙋举个栗子:

需求:给你任何一个类型的数组,都能返回它的内容,也就是实现Arrays.toString(数组)的功能

public class Demo {
    public static void main(String[] args) {
        String[] names={"小明","拉拉","小子"};
        printArray(names); // [小明,拉拉,小子]

        Integer[] nums={12,34,67};
        printArray(nums); // [12,34,67]
    }

    public static <T> void printArray(T[] arr) {
        if (arr != null) {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < arr.length; i++) {
                sb.append(arr[i]).append(i == arr.length - 1 ? "]" : ",");
            }
            System.out.println(sb);
        } else {
            System.out.println(arr);
        }
    }
}

🙋🙋 再举个栗子:

定义一个泛型方法,传递一个集合和四个元素,将元素添加到集合中并返回

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list1 = addElement(new ArrayList<String>(), "a", "b", "c", "d");
        System.out.println(list1); // [a, b, c, d]

        ArrayList<Integer> list2 = addElement(new ArrayList<Integer>(), 1, 2, 3, 4);
        System.out.println(list2); // [1, 2, 3, 4]
    }

    public static <T> ArrayList<T> addElement(ArrayList<T> list, T t1, T t2, T t3, T t4) {
        list.add(t1);
        list.add(t2);
        list.add(t3);
        list.add(t4);
        return list;
    }
}

泛型方法的原理:

  • 把出现泛型变量的地方全部替换成传输的真实数据类型

2.4 自定义泛型接口


使用了泛型定义的接口就是泛型接口,其作用是可以让实现类选择当前需要操作的数据类型

泛型接口格式:

修饰符 interface 接口名<类型> {  }

范例:

public interface Generic<T>{}

🙋举个栗子:

需求:教务系统,提供一个接口,可约束一定要完成的数据(学生、老师)的增删改查操作

老师类

public class Teacher {
}

学生类

public class Student {
}

自定义泛型接口

public interface Data<E> {
    void add(E e);
    void delete(int id);
    void update(E e);
    void query(int id);
}

学生数据的增删改查

public class StudentData implements Data<Student>{
    @Override
    public void add(Student student) {

    }

    @Override
    public void delete(int id) {

    }

    @Override
    public void update(Student student) {

    }

    @Override
    public void query(int id) {

    }
}

老师数据的增删改查

public class TeacherData implements Data<Teacher>{
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public void delete(int id) {

    }

    @Override
    public void update(Teacher teacher) {

    }

    @Override
    public void query(int id) {

    }
}

泛型接口的使用方式:

  • 实现类也不给具体的泛型
  • 实现类确定具体的数据类型

泛型接口的原理:

  • 实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对该类型的操作

2.5 类型通配符


ETKV是在 定义 泛型的时候使用的
? 可以在 使用 泛型的时候代表一切类型

类型通配符:<?>

  • ArrayList<?>:表示元素类型未知的 ArrayList,它的元素可以匹配任何的类型
  • 但是并不能把元素添加到 ArrayList中了,获取出来的也是父类类型

类型通配符上限:<? extends 类型>

  • ArrayListList <? extends Number>:它表示的类型是Number或者其子类型

类型通配符下限:<? super 类型>

  • ArrayListList <? super Number>: 它表示的类型是Number或者其父类型

🙋举个栗子:

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<String> list2 = new ArrayList<>();
        ArrayList<Number> list3 = new ArrayList<>();
        ArrayList<Object> list4 = new ArrayList<>();

        method(list1);
        method(list2);
        method(list3);
        method(list4);

        getElement1(list1);
        getElement1(list2);//报错
        getElement1(list3);
        getElement1(list4);//报错

        getElement2(list1);//报错
        getElement2(list2);//报错
        getElement2(list3);
        getElement2(list4);
    }

    // 泛型通配符: 此时的泛型?,可以是任意类型
    public static void method(ArrayList<?> list) {
    }

    // 泛型的上限: 此时的泛型?,必须是Number类型或者Number类型的子类
    public static void getElement1(ArrayList<? extends Number> list) {
    }

    // 泛型的下限: 此时的泛型?,必须是Number类型或者Number类型的父类
    public static void getElement2(ArrayList<? super Number> list) {
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值