目录
一、包装类
1.1 定义和由来
包装类就是把8大基本类型包装起来。
Object类可以接收所有引用类型(数组,类,接口),为了让Object类可以接收Java的所有内容,引入了包装类,将基本类型的数值封装到类的对象之中。
基本类型的默认值在实际应用场景下会产生误导,引用类型的默认值是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
上述代码过于繁琐,Java编译器对其进行了优化,自动拆装箱,即使用包装类和使用基本类型一模一样
//自动装箱
Integer i2 = 10;
// 自动拆箱
i2 += 20;
System.out.println(i2);
输出:
30
1.4 包装类和基本类型的区别
- 默认值不同,包装类的默认值都是null,基本类型的默认值跟其数据类型有关。
- 比较相等,包装类使用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
当使用整型包装类的自动拆装向时,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)
当用户输入的两个值不是相同类型的时候,编译时没问题的,但下面强制类型转换,要打印的时候会报错,产生运行时异常-类型转换异常。所以我们用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度
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
上面使用不同的大写字母指代不同的类型,下面指代的时候两个类型可以相同,也可以不相同。
三、集合
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
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]]
上述代码就是一个二维数组,List里面套了一个List
相当于 int[] [] data = new int[] []
四、总结
以上论述时学习数据结构的基础,必掌握!!!!