Java学习(十四)数据结构、泛型
一、数据结构
- 数据结构其实就是存储数据的格式
- 分类:
栈 , 队列 , 数组 , 链表 , 树 , 哈希表,图,堆
1.数组
数组是一种线性结构,而且在物理内存中也占据着一块连续空间。
优点:访问数据简单。
缺点:添加和删除数据比较耗时间。
使用场景:频繁查询,对存储空间要求不大,很少增加和删除的情况。
数据访问:由于数据是存储在连续空间内,所以每个数据的内存地址都是通过数据小标算出,所以可以直接访问目标数据。(这叫做“随机访问”)。
2.链表
链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。
优点:数据添加和删除方便
缺点:访问比较耗费时间
适用场景:数据量较小,需要频繁增加,删除操作的场景
数据访问:因为数据都是分散存储的,所以想要访问数据,只能从第一个数据开始,顺着指针的指向逐一往下访问。
3.栈
栈也是一种数据呈线性排列的数据结构,不过在这种结构中,我们只能访问最新添加的数
据。从栈顶放入元素的操作叫入栈,取出元素叫出栈。
特点:后进先出(Last In First Out,简称LIFO)
4.队列
队列中的添加和删除数据的操作分别是在两端进行的。队列可以在一端添加元素,在另一端取出元素,也就是:先进先出(First In First Out,简称FIFO)
5.哈希表
哈希表,也叫散列表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。
6.堆
堆是一种图的树形结构,被用于实现“优先队列”(priority queues)。优先队列是一种数据结构,可以自由添加数据,但取出数据时要从最小值开始按顺序取出。在堆的树形结构中,各个顶点被称为“结点”(node),数据就存储在这些结点中。堆有下列特点:
每个节点最多有两个子节点
排列顺序必须从上到下,同一行从左到右
堆中某个节点的值总是不大于或不小于其父节点的值;
存放数据时,一般会把新数据放在最下面一行靠左的位置。如果最下面一行没有多余空间时,就再往下另起一行,并把数据添加到这一行的最左端。
7.树
它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;
没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;
除了根节点外,每个子节点可以分为多个不相交的子树;
8.图
图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。按照顶点指向的方向可分为无向图和有向图:
二、泛型
- 泛型概述
是一种把类型明确的工作,推迟到创建对象或者调用方法的时候才去明确的特殊的类型。
参数化类型,把类型当作参数一样的传递。
- 泛型的格式
<数据类型> 这里的数据类型只能是引用数据类型
- 泛型好处
(1): 把运行时期的问题提前到了编译期间
(2): 避免了强制类型转换
(3):优化了程序设计,解决了黄色警告线
注意:泛型只在编译期有效 但在运行期就擦除了
验证:
public class Test {
public static void main(String[] args) throws Exception {
第一个list1我们只创建了一个容器:可以输入任何类型
ArrayList list1=new ArrayList();
第二个list2我们创建了一个泛型:只能输入String类型
ArrayList<String> list2=new ArrayList<String>();
使用反射机制,获取Class
Class c1=list1.getClass();
Class c2=list2.getClass();
疑问:在运行时,他们俩相等嘛?
System.out.print(c1==c2);
}
}
输出肯定是true。因为泛型只在编译器有效,在运行时期无效,也就变成了一样的。
原理:
Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。
使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。
如在代码中定义的List<object>和List<String>等类型,在编译后都会编程List。JVM看到的只是List,
而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免
在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式间的重要区别。
泛型使用
1.泛型类:把泛型定义在类上
public class 类名<泛型类型1,…>
2.泛型方法:把泛型定义在方法上
public <泛型类型> 返回类型 方法名(泛型类型 变量名)
3.泛型接口:把泛型定义在接口上
public interface 接口名<泛型类型>
泛型通配符
泛型通配符<?>: 任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E: 向下限定,E及其子类
? super E: 向上限定,E及其父类