当前位置:   article > 正文

Java入门——包装类和泛型_java 封装泛型

java 封装泛型

一、包装类

1.1 定义和由来

包装类就是把8大基本类型包装起来。

  1. Object类可以接收所有引用类型(数组,类,接口),为了让Object类可以接收Java的所有内容,引入了包装类,将基本类型的数值封装到类的对象之中。

  2. 基本类型的默认值在实际应用场景下会产生误导,引用类型的默认值是Null,下面举个例子。

    double的默认值:0.0

    现在有一个扣费的需求,当我们扣费成功后,余额为0.0了,如果是默认值,我们无法得知是否发生了扣费。所以使用double的包装类-Double,默认值是Null。

1.2 包装类分类

在这里插入图片描述

1.3 包装类的使用

拆箱:将基本类型的数值保存在包装对象中

装箱:将包装类对象中的数值还原为基本类型

以下展示int和Integer的相互转换

public static void main(String[] args) {
    int val = 10;
    // int -> Integer,装箱
    Integer i1 = new Integer(val);
    Object obj = i1;
    // 需要进行数学运算,拆箱
    int ret = i1.intValue();
    //查看i1的类型
    System.out.println(i1.getClass().getName());
}
输出:
java.lang.Integer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

上述代码过于繁琐,Java编译器对其进行了优化,自动拆装箱,即使用包装类和使用基本类型一模一样

//自动装箱
Integer i2 = 10;
// 自动拆箱
i2 += 20;
System.out.println(i2);

输出:
30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

1.4 包装类和基本类型的区别

  1. 默认值不同,包装类的默认值都是null,基本类型的默认值跟其数据类型有关。
  2. 比较相等,包装类使用equals方法,因为他是一个引用类型,所有类对象的比较都是用equals方法。
Integer i1 = 130;
Integer i2 = 130;
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
i1 = 120;
i2 = 120;
System.out.println(i1 == i2);

输出:
false
true
true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

当使用整型包装类的自动拆装向时,JVM会缓存相应的数值。Integer常量池,默认在-128到127之间取值,都会缓存在常量池中。

i1创建一个Integer对象保存到常量池中,此时120已在常量池中有了,i2直接复用。

二、泛型

先看一串代码

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 point = new Point();
        // 要求x和y必须是相同类型
        point.setX(10);
        point.setY("北纬30度");
        String x = (String) point.getX();
        String y = (String) point.getY();
        System.out.println("x = " + x + ", y = " + y);
    }
}
输出:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
	at generic_test.Point.main(Point.java:45)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

当用户输入的两个值不是相同类型的时候,编译时没问题的,但下面强制类型转换,要打印的时候会报错,产生运行时异常-类型转换异常。所以我们用Object类来接受类型的时候,会产生因为类型不一致导致的异常。由此,引入泛型。

2.1 泛型的定义

泛型指的是在类定义时不明确类型,在使用时明确类型。其目的是在编译阶段检查类型是否一致的手段。

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

定义类称为类型参数:可以使用任意字符,规范是用单个的大写字母

常用类型参数:

T:表示任意类型

K:键值对

V:value值

E:单个元素

public class MyPoint<T> {
    // 此时x的类型不定,在产生这个对象时确定类型
    private T x;
    private T y;

    public T getX() {
        return x;
    }

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

    public T getY() {
        return y;
    }

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

    public static void main(String[] args) {
        // 设置的类型就是字符串
        MyPoint<String> point = new MyPoint<>();
        point.setX("东经20度");
        point.setY("北纬20度");
        String x = point.getX();
        String y = point.getY();
        System.out.println("x = " + x + ", y = " + y);
    }
}

输出:
x = 东经20, y = 北纬20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

x和y两个成员变量在定义事类型不确定,在产生对象时明确x和y的类型。当产生MyPoint对象是,T会替换成String类型,这样避免了强制类型转换。

2.2 泛型的好处

引入泛型后,可以在编译阶段检查设置的类型是否是指定类型,若不一致,编译报错。在取值的时候,无需在进行强转。

2.3 举例

上面代码都是成员类型一致的情况,当成员类型不一致的时候又怎么办呢?这时可以使用多个类型参数。

public class MyPointNew<T,E> {
        private T x;
        private E y;

        public T getX() {
            return x;
        }

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

        public E getY() {
            return y;
        }

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

        public static void main(String[] args) {
            MyPointNew<String,Integer> pointNew = new MyPointNew<>();
            String x = pointNew.getX();
            int y = pointNew.getY();
            System.out.println("x = " + x + " " + "y = " + y);
            MyPointNew<Integer,Integer> pointNew1 = new MyPointNew<>();
            pointNew1.setX(10);
            pointNew1.setY(10);
        }
}
输出:
x = 123 y = 123
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

上面使用不同的大写字母指代不同的类型,下面指代的时候两个类型可以相同,也可以不相同。

三、集合

3.1 集合的定义与分类

集合,其实就是用来保存和操作数据的一些类,是一个容器,以动态的把多个对象的引用放入容器中。

类别
在这里插入图片描述

Collection及其子类:线性表集合,保存单个同类型元素。

ArrayList:动态数组

LinkList:双向链表

Map集合:键值对集合,保存一对元素。<key,value>,映射关系,key值不重复,value可以重复

HashMap:哈希表

TreeMap:二分平衡搜索树-红黑树

PriorityQueue:堆,默认是最小堆

3.2 List接口及其子类

List-线性表的父接口

常用子类-ArrayList(基于动态数组实现的线性表)

LinkList(基于双向链表实现的线性表)

3.2.1 List及其子类的的常用方法

数据结构的方法几乎都是增删改查

List

方法含义
boolean add(E e)尾插e
void add(int index,E element)将e插入到index位置
boolean addAll(Collection<? extends E> c)尾插c中的元素
E remove(int index)删除index位置的元素
boolean remove(Object 0)删除遇到的第一个o
E get(int index)获取下标index位置的元素
E set(int index,E element)将下标index位置元素设置为element
void clear()清空
boolean contains(Object o)判断o是否在线性表中
int indexOf(Object o)返回第一个o所在下标
int lastIndexOf(Object o)返回最后一个o的下标
List subList(int fromindex,int toIndex)截取部分list

ArrayList(顺序表)

方法含义
ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其它Collection构建ArratList
ArrayList(int initialCapacity)指定顺序表初始容量

LinkedList(链表)

方法含义
LinkedList()无参构造
public class ListTest {
    public static void main(String[] args) {
    	//创建一个整形的顺序表
    	List<Integer> list = new ArrayList<>()
 		//创建一个整形的链表
        List<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(3);
        list.add(5);
        list.add(7);
        list.add(9);
        list.add(1,20);
        System.out.println(list);
        System.out.println(list.get(3));
        // 7
        System.out.println(list.set(4,100));
    }
}
输出:
[1, 20, 3, 5, 7, 9]
5
7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

List接口中定义的方法,子类在实现时都需要覆写。

在使用时更换子类,是要更换new的子类对象。在使用时没有任何区别,因为方法在接口中都定义好了,子类只是做一个实现。

看一个代码

public static void main(String[] args) {
    List<List<Integer>> list = new ArrayList<>();
    List<Integer> list1 = new ArrayList<>();
    //第一行
    list1.add(1);
    list1.add(3);
    list1.add(5);
    List<Integer> list2 = new ArrayList<>();
    //第二行
    list2.add(2);
    list2.add(4);
    list2.add(6);
    list.add(list1);
    list.add(list2);
    System.out.println(list);
}
输出:
[[1, 3, 5], [2, 4, 6]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上述代码就是一个二维数组,List里面套了一个List

相当于 int[] [] data = new int[] []

四、总结

以上论述时学习数据结构的基础,必掌握!!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/1020902
推荐阅读
相关标签
  

闽ICP备14008679号