第7章:对象的容纳
- 1.数组 Arrays
- 1.1 数组的创建、初始化和使用
- (1)数组的声明
- (2)数组初始化
- 静态初始化
- 动态初始化
- 对象数组的初始化
- (3)数组的使用
- 1.2 多维数组
- 1.3 数组与数组的引用
- 1.4 数组工具类Arrays
- 1.5 数组对象比较接口
- 1.6 数组的优缺点
- 优点
- 缺点
- 2.枚举 enum
- 3.容器 Collection(“集合接口”)
- 容器类关系
- Collection接口
- 3.1 列表 List
- (1)ArrayList 线性表
- (2)LinkedList 链表
- 3.2 泛型
- (1)使用泛型的语法
- (2)泛型的使用
- (3)容器的泛型
- 3.3 Set 集合
- (1)Iterator(迭代器)遍历
- (2)for-each遍历
- (3)HashSet 哈希集、散列集
- (4)其他Set
- 3.4 Map 映射
- Map常用方法
- (1)Map遍历
- (2)HashMap 哈希映射
- (3)其他Map
- 3.5 Collections 工具类
- 容器完整关系图
- 3.6 容器类型选择
- 4.泛型中的通配符
- 4.1 通配符简介
- 4.2 无界通配符“?”
- 4.2 通配符上界“? extends T”
- 4.3 通配符下界“? super T”
- 泛型通配符小结
- 总结
1.数组 Arrays
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于
该对象的成员变量 - 数组中的元素可以是任何数据类型,包括基本类型和引用类型
1.1 数组的创建、初始化和使用
(1)数组的声明
- “[]”表示声明的变量是一个数组类型,例:int a1[ ]; int [ ] a2; String [ ] b; Person [ ] p1;
- Java语言中声明数组时不能指定其长度(数组中元素的个数),例如:int a[5]; //非法
(2)数组初始化
- 数组在声明之后还不可以使用,在使用数组之前必须为数组分配足够的系统资源,称为“初始化”
静态初始化
动态初始化
对象数组的初始化
- 对于第二种对象数组的初始化方法,除了创建时要用new,在初始化时也要用new。第一次new只是创建了三个引用变量,第二次new才创建了对象,如下面三张图所示。
(3)数组的使用
- 按照索引访问数组元素,同C++
- Java中的数组也是对象,除了数组元素之外,还存在唯一一个可被访问的属性length,记录了数组中元素的个数,不像C++那样得调用函数,例如:a[a.length-1]代表数组中最后一个元素
1.2 多维数组
- 存在不规则数组
1.3 数组与数组的引用
- Java数组是特殊的对象,数组变量存放一个数组对象的引用
- 可以将数组变量作为方法参数达到改变数组元素值的效果
例:Java中引用是通过值传递的。在changeArrayValue中,令para=a,引用的是同一块区域,因此修改para[0]时,实际上是修改了这块区域内的元素值,a[0]也对应改变。而在changeArrayRef中,para一开始等于a,但又令para=temp,这时para不再与a引用相同区域,而是与temp引用相同区域,a[0]仍为99。
1.4 数组工具类Arrays
1.5 数组对象比较接口
先将Object o转换为Employee类型的e,用this表示比较发起者
1.6 数组的优缺点
优点
- 数组可以快速地随机访问数组中的元素。数组可以保存基本类型和对象。
- Arrays类,专门用来操作array。
缺点
- 数组的容量固定。当数组空间不足的时候需要做数据迁移,效率很低。
- 注意:数组声明时不能指定长度,但是初始化时固定了数组的大小
- 经常或者通常情况下,编程人员不知道或无法确定正在编写的程序需要使用多少个对象。
2.枚举 enum
- 适用于某些数据集合,它们的数值是不变化的,而且集合中的元素个数是有限的,例如:季节、性别、星期
3.容器 Collection(“集合接口”)
- 不同于数组,容器的容量是动态的
- Collection(类集): 一组单独元素集合
- List :保存的对象有顺序,按照元素的索引位置检索对象。允许重复元素。
- Set :不允许保存重复的元素。元素之间没有顺序。靠元素值检索对象。
- Map(映射): 一组键值对
- 元素包括“键” 对象和“值”对象。键必须是唯一的,值可以重复
容器类关系
Collection接口
3.1 列表 List
- List常用实现类有ArrayList和LinkedList,两种类型存在性能差异
- ArrayList与LinkedList常用的大部分方法都是接口List定义的
- 使用接口List定义类集的方法有一个好处:改变集合类型时其它代码不用变化。例如:
- 当使用实现类特有方法时不能使用接口定义:List a= new ArrayList();而应该使用具体类定义:ArrayList a = new ArrayList();
(1)ArrayList 线性表
- 也被称为动态数组,类似C++的vector
- 内部维护了一个Object类型数组
(2)LinkedList 链表
- 较快的顺序存取速度。快速的中间插入删除速度。随机存取速度较低。
- 内部维护了一个带头结点的双向链表
3.2 泛型
- 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
为什么要用泛型? | 泛型方法、通配符该如何使用 | Java中的泛型知识
(1)使用泛型的语法
- 在声明泛型类的变量时,使用尖括号“<>”来指定形式类型参数
- class 类名<类型参数列表> {类体}
- 例:class A <X1,X2> {X1 a; X2 b;}
- 在应用泛型类时,必须用具体类型填入类型参数,即泛型类的具体化
- 类名<具体类型列表> 变量名=new 类名<具体类型列表>(构造函数的参数列表);
- 例:A<String,Integer> m = new A<String,Integer>();
(2)泛型的使用
- 类,接口,方法都可以使用泛型
(3)容器的泛型
3.3 Set 集合
- 继承自Collection 接口。没有额外的方法。
- 常用的实现类:HashSet 和 TreeSet以及LinkedHashSet。
(1)Iterator(迭代器)遍历
- 调用方法iterator() 返回一个迭代器。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
- 使用**next()**获得序列中的下一个元素,每成功调用一次迭代器向后移动一个元素。
- 使用**hasNext()**检查序列中是否还有元素。
- 使用**remove()**将迭代器新返回的元素删除。
- 接口ListIterator从接口Iterator继承,它可以从两个方向遍历List
- Collection接口都可以使用迭代器
(2)for-each遍历
- for-each只能遍历两种类型的对象:
- 数组
- 实现了java.lang.Iterable接口的类的实例
(3)HashSet 哈希集、散列集
- 添加删除时,若循环比较则效率低下
- 采用“哈希表”与哈希算法实现快速查找
- 内部维护一个链表数组(是“链表”和“数组”的组合)
- 拥有常数查找时间
- 要求对象重写hashCode()方法与equals()方法
(4)其他Set
- 比较HashSet,TreeSet,LinkedHashSet
- HashSet的元素存放无顺序
- LinkedHashSet保持元素的添加顺序
- TreeSet元素按值进行排序存放(默认从小到大)
3.4 Map 映射
- 一个Map中不能包含相同的key,每个key只能映射一个value。
- 常用的实现类:HashMap和TreeMap以及LinkedHashMap。
Map常用方法
(1)Map遍历
- Map接口没有实现Iterable接口,无法使用迭代器
- Map键值对元素无序,无法使用索引
- Map接口提供3种集合的视图:
- keySet():生成键的Set型集合
- values():生成值的Collection型集合
- entrySet():生成键值对的Set型集合
(2)HashMap 哈希映射
- HashSet内部维护着一个HashMap
- HashMap的对象也需要实现 equals()与hashCode() 方法
- 键是唯一的,因此再put dog,red的时候,dog的值改变为red
(3)其他Map
3.5 Collections 工具类
容器完整关系图
3.6 容器类型选择
4.泛型中的通配符
4.1 通配符简介
- Java泛型是强类型检测的,泛型类型的子类型互不相关。为了使泛型类型具有面向对象的继承关系,Java引入了通配符的概念。
4.2 无界通配符“?”
4.2 通配符上界“? extends T”
4.3 通配符下界“? super T”