1.1.1认识集合
开发应用程序时,如果想存储多个同类型的数据,可以使用数组来实现;但是使用数组存在如下一些明显缺陷:(1)数组长度固定不变,不能很好地适用元素数量动态变化的情况。
(2)可通过数组名.length获取数组的长度,却无法直接获取数组中实际存储的元素个数。
(3)数组采用在内存中分配连续空间的存储方式存储,根据元素信息查找时效率比较低,需要多次比较。
从以上分析可以看出数组在处理一些问题时存在明显的缺陷,针对数组的缺陷,Java提供了比数组更灵活、更实用的集合框架,可大大提高软件的开发效率,并且不同的集合可适用于不同应用场合。
Java集合框架提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中。
Java的集合类主要由Map接口和Collection接口派生而来,其中Collection接口有两个常用的子接口,即List接口和Set接口,所以通常说Java集合框架由三大类接口构成(Map接口、List接口和Set接口)。
1.1.2 List接口
Collection接口是最基本的集合接口,可以存储一组不唯一、无序的对象。List接口继承自Collection接口,是有序集合。用户可使用索引访问List接口中的元素,类似于数组。List接口中允许存放重复元素,也就是说List可以存储一组不唯一、有序的对象。
List接口常用的实现类有ArrayList和LinkedList。
1.使用ArrayList类动态存储数据
针对数组的一些缺陷,Java集合框架提供了ArrayList集合类,对数组进行了封装,实现了长度可变的数组,而且和数组采用相同的存储方式,在内存中分配连续的空间,经常称ArrayList为动态数组。但是它不等同于数组,ArrayList集合中可以添加任何类型的数据,并且添加的数据都将转换成Object类型,而在数组中只能添加同一数据类型的数据。
ArrayList类的常用方法
方法 | 说明 |
boolean add(Object o) | 在列表的末尾添加元素o,起始索引位置从0开始 |
void add(int index,Object o) | 在指定的索引位置添加元素0,索引位置必须介于0和列表中的元素个数之间 |
int size() | 返回列表中的元素个数 |
Object get(int index) | 返回指定索引位置处的元素,取出的元素是Object类型,使用前需要进行强制类型转换 |
void set(int index ,Object obj) | 将index索引位置的元素替换为obj元素 |
boolean contains(Object o) | 判断列表中是否存在指定元素o |
int indexOf(Object obj) | 返回元素在集合中出现的索引位置 |
boolean remove(Object o) | 从列表中删除元素o |
Object remove(int index) | 从列表中删除指定位置的元素,起始索引位置从0开始 |
在ArrayList集合中可以存储任何类型的对象。其中,代码List newsTitleList new ArrayListO;是将接口List 的引用指向实现类ArrayList的对象。在编程中将接口的引用指向实现类的对象是Java实现多
态的一种形式,也是软件开发中实现低耦合的方式之一,这样的用法可以大大提高程序的灵活性。随着编程经验的积累,开发者对这个用法的理解会逐步加深
ArrayList集合因为可以使用索引来直接获取元素,所以其优点是遍历元素和随机访问元素的效率比较高。但是由于ArrayList 集合采用了和数组相同的存储方式,在内存中分配连续的空间,因此在添加和删除非尾部元素时会导致后面所有元素的移动,这就造成在插入、删除等操作频繁的应用场景下使用ArrayList会导致性能低下。所以数据操作频繁时,最好使用LinkedList存储数据。
2.使用LinkedList类动态存储数据
LinkedList类是List接口的链接列表实现类。它支持实现所有List 接口可选的列表的操作,并且允许元素值是任何数据,包括null.LinkedList类采用链表存储方式存储数据。
LinkedList 类和ArrayList类所包含的大部分方法是完全一样的, 这主要是因为它们都是List接口的实现类。由于ArrayList采用和数组一样的连续的顺序存储方式,当对数据频繁检索时效率较高,而LinkedList类采用链表存储方式,当对数据添加、删除或修改比较多时,建议选择LinkedList类存储数据。
1.1.3 Set接口
1.Set接口概述
Set接口是Collection接口的另外-一个常用子接口,Set 接口描述的是一种比较简单的集合。集合中的对象并不按特定的方式排序,并且不能保存重复的对象,也就是说Set接口可以存储一 组一、 无序的对象。Set接口常用的实现类有HashSet。
2.使用HashSet类动态存储数据
假如现在需要在很多数据中查找某个数据,LinkedList 类就无需考虑了,它的数据结构决定了它的查找效率低下。如果使用ArrayList类,在不知道数据的索引且需要全部遍历的情况下,效率一样很低下。为此Java集合框架提供了一个查找效率高的集合类HashSet。HashSet 类实现了Set 接口,是使用Set集合时最常用的一个实现类。HashSet集合的特点如下:
(1)集合内的元素是无序排列的。
(2)HashSet 类是非线程安全的。
(3)允许集合元素值为null。
1.1.4 Iterator接口
Ilerator接口表示对集合进行迭代的迭代器。Iterator 接口为集合而生,专门实现集合的通历。此接口主要有如下两个方法:
(1)haNext); 判断尼香存在下一个可访问的元素,如果仍有元素可以迭代,则返回true.
(2)next(: 返回要访问的下一个元素。
凡是由Cllection接口派生而来的接口或者类,都实现了iterateO 方法,iterateo 方法返回一个lterator 对象。
2.使用Iterator遍历集含
使用Iterator接口遍历ArrayList集合。
实现步骤如下。
(1)导入Iterator接口。
(2)使用集合的iterate()方法返回Iterator对象。
(3) while 循环遍历。
(4)使用Iterator的hasNext()方法判断是否存在下一个可访问的元素。
(5)使用Iterator的next()方法返回要访问的下一个元素。
1.1.5 Map接口
1. Map接口概述
Map接口存储组成对的键 (key)一值(value)对象,提供key到value的映射,通过key来检索。Map接口中的key不要求有序,不允许重复。value 同样不要求有序,但允许重复。
Map接口中存储的数据都是键一值对, 例如, 个身份证号码对应个人,其中身份证号码就是key,与此号码对应的人就是value。
2.使用HashMap类动态存储数据
最常用的Map实现类是HashMap,其优点是查询指定元素效率阎。
使用HashMap类存储学生信息,要求可以根据英文名检索学生信息。
实现步骤如下:
(1)导入HashMap类。
(2)创建HashMap对象。
(3)调用HashMap对象的put() 方法,向集合中添加数据。
(4)输出学员个数。
(5)输出键集。
(6)判断是否存在“Jack"这个键,如果存在,则根据键获取相应的值。
(7)判断是否存在“Rose”这个键,如果存在,则根据键获取相应的值。
1.1.Collections类
collections类是Java提供的一个集合操作工具类,它包含了大量的静态方法,用于实现对集合元素的排序、查找和替换等操作。
1.对集合元素排序与查找
排序是针对集合的一个常见需求。要排序就要知道两个元素哪个大哪个小。在Java中,如果想实现一个类的对象之间比较大小,那么这个类就要实现Comparable接口。此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo()方法被称为它的自然比较方法。此方法用于比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
compareTo()方法的定义语法格式如下:int compareTo(Object obj);
其中:参数: obj即要比较的对象;
返回值:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象返回不同的值。
实现此接口的对象列表(和数组)可以通过Clletions sort()方法(和Aray.sorto方法)进行自动排序。示例8通过实现Comparable接口对集合进行排序。
2.替换集合的元素
若有一个需求,需要把一个List集合中的所有元素都替换为相同的元素,则可以使用Collections类的静态方法fill()来实现。
使用Collections类的静态方法fill()替换List集合中的所有元素为相同的元素。
实现步骤如下:(1)导入相关类,初始化数据。
(2)使用Collections类的fill()方法替换集合中的元素。
(3)遍历输出替换后的集合。
1.2.1 认识泛型
泛型是JDK 1.5 的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,使代码可以应用于多种类型。简单说来,Java 语言引入泛型的好处是安全简单,且所有强制转换都是自动和隐式进行的,提高了代码的重用率。
1.泛型的定义
将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛型。泛型的本质就是参数化类型。
泛型的定义语法格式如下:类1或者接口<类型实参>对象=new类2<类型实参>0;
2.泛型在集合中的应用
add()方法的参数是Object类型,不管把什么对象放入List接口及其子接口或实现类中,都会被转换为Object类型。Map接口中使用put()方法和get()方法存取对象时,以及使用Iterator的next()方法获取元素时存在同样的问题。
使用泛型集合在创建集合对象时指定集合中元素的类型,从集合中取出元素时无需进行强制类型转换,并且如果把非指定类型对象放入集合,会出现编译错误。
List和ArrayList的泛型形式是List<E>和ArrayList<E>,ArrayList<E> 与ArrayList类的常用方法基本一样。
同样的,Map 与HashMap也有它们的泛型形式,即Map<K,V>和HashMap<K,V>.因为它们的每一个元素都包含两个部分,即key和value,所以,在应用泛型时,要同时指定key的类型和value的类型,K表示key的类型,V表示value的类型。HashMap<K,V>操作数据的方法与HashMap基本一样。
1.2.2 深入泛型
参数化类型:参数化类型包含一个类或者接口, 以及实际的类型参数列表。
类型变量: 是一种非限定性标识符, 用来指定类、接口或者方法的类型。
1.定义泛型类、泛型接口和泛型方法
对于一些常常处理不同类型数据转换的接口或者类,可以使用泛型定义,如Java中的List接口。定义泛型接口或类的过程,与定义个接口或者类相似。
(1)泛型类
泛型类简单地说就是具有一个或者多个类型参数的类。
定义泛型类的语法格式如下:访问修饰符class cassNams-TypeLis
TypeList表示类型参数列表,每个类型变量之间以逗号分隔。
创建泛型类实例的语法格式如下:new cassName Typel st(argLis);
TypeList表示定义的类型参数列表,每个类型变量之间以逗号分隔。
argList表示实际传递的类型参数列表,每个类型变量之间同样以逗号分隔。
(2)泛型接口
泛型接口就是拥有一个或多个类型参数的接口。泛型接口的定义方式与定义泛型类类似。
定义泛型接口的语法格式如下:访问修饰符interface interfaceName-TypeList>
TypeList表示由逗号分隔的一一个或多个类型参数列表。
泛型类实现泛型接口的语法格式如下:访问修饰符class className<TypeList>imliements interfanceName<TypeList>
(3)泛型方法
泛型方法实际上就是带有类型参数的方法。需要特别注意的是,定义泛型方法与方法所在的类、或者接口是否是泛型类或者泛型接口没有直接的联系,也就是说无论是泛型类还是非泛型类,如果需要就可以定义泛型方法。
定义泛型方法的语法格式如下:访问修饰符<类型参数>返回值方法名(类型参数列是)
2.多个参数的泛型类
泛型类的类型参数都只有一个,实际上类型参数可以有多个,如HashMap<K,V>就有两个类型参数,一一个指定key的类型。一个指定valule的类型。下面介绍如何自定义一个包含多 个类型参数的泛型类。
定义泛型类,并设置两个类型参数。
实现步骤如下:定义泛型类。实例化泛型类。
3.从泛型类派生子类
面向对象的特性同样适用于泛型类,所以泛型类也可以继承。不过,继承了泛型类的子类,必须也是泛型类。
继承泛型类的语法格式如下:class子类<T> extends父类<T>{}
定义泛型父类,同时定义一个泛型子类继承泛型父类。
实现步骤如下:
(1)定义父类FarmeT, 并添加整型字段plantNum. 方法plantCrop(T crop)
(2)定义子类FruitFarm <T>,重写方法plantCrop(List<T> list)。