赞
踩
包装类就是把8大基本类型包装起来。
Object类可以接收所有引用类型(数组,类,接口),为了让Object类可以接收Java的所有内容,引入了包装类,将基本类型的数值封装到类的对象之中。
基本类型的默认值在实际应用场景下会产生误导,引用类型的默认值是Null,下面举个例子。
double的默认值:0.0
现在有一个扣费的需求,当我们扣费成功后,余额为0.0了,如果是默认值,我们无法得知是否发生了扣费。所以使用double的包装类-Double,默认值是Null。
拆箱:将基本类型的数值保存在包装对象中
装箱:将包装类对象中的数值还原为基本类型
以下展示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
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类来接受类型的时候,会产生因为类型不一致导致的异常。由此,引入泛型。
泛型指的是在类定义时不明确类型,在使用时明确类型。其目的是在编译阶段检查类型是否一致的手段。
定义泛型使用"< >"操作符
定义类称为类型参数:可以使用任意字符,规范是用单个的大写字母
常用类型参数:
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类型,这样避免了强制类型转换。
引入泛型后,可以在编译阶段检查设置的类型是否是指定类型,若不一致,编译报错。在取值的时候,无需在进行强转。
上面代码都是成员类型一致的情况,当成员类型不一致的时候又怎么办呢?这时可以使用多个类型参数。
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
上面使用不同的大写字母指代不同的类型,下面指代的时候两个类型可以相同,也可以不相同。
集合,其实就是用来保存和操作数据的一些类,是一个容器,以动态的把多个对象的引用放入容器中。
类别
Collection及其子类:线性表集合,保存单个同类型元素。
ArrayList:动态数组
LinkList:双向链表
Map集合:键值对集合,保存一对元素。<key,value>,映射关系,key值不重复,value可以重复
HashMap:哈希表
TreeMap:二分平衡搜索树-红黑树
PriorityQueue:堆,默认是最小堆
List-线性表的父接口
常用子类-ArrayList(基于动态数组实现的线性表)
LinkList(基于双向链表实现的线性表)
数据结构的方法几乎都是增删改查
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[] []
以上论述时学习数据结构的基础,必掌握!!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。