Java集合框架学习(ArrayList、Set、Collection、Vector、Enumeration、Map、Iterator)
一、前言引入
集合框架就是java是实现的数据结构,或者简单点说,所谓的类集指的是对象数组的引用。之前保存多个对象,使用的是数组,但数组的长度是固定的。后来使用了链表实现了一个动态的对象数组。
- 链表的开发麻烦;
- 链表的操作性能不好;
- 链表使用了Object类进行保存,所有的对象必须向上转型以及强制性向下转型的操作;
综上,得出结论:提供了一个与链表类似的工具类——Vector(向量),后来发现这个类并不能很好的进行项目的开发,所以从Java2(JDK1.2之后)提供了一个专门实现数据结构的开发框架——类集框架,并且在JDK1.5之后泛型技术的引入,又解决了类集框架中都使用Object所带来的安全隐患。
随后在JDk1.8之后,又针对类集的大数据操作环境下推出了数据流的分析操作功能。
在整个类集之中有以下几个核心接口:
-
Collection、List、Set;
-
Map;
-
Iterator、Enumeration。
接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map
等。之所以定义多个接口,是为了以不同的方式操作集合对象
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
二、具体内容
2.1 collection接口
Collection是整个类集之中单值保存的最大父接口。即:每一次可以向集合里面保存一个对象。
public interface Collection<E>extends Iterable<E>
Public boolean add(E e) | 向集合中加入元素 |
Public boolean addAll(Collection<? extends E> e) | 追加一个集合 |
Public void clear() | 清空集合,根元素为null |
Public boolean contains(Object o) | 判断是否包含此元素(区分大小写) |
Public boolean isEmpty() | 判断是否不包含元素 |
Public boolean remove() | 删除单个实例 |
Public int size() | 集合中的元素个数 |
Public Object[] toArray() | 将集合变为对象数组保存 |
Public Iterator iterator() | 为Iterator接口实例化 |
由于开发的严格性一般不会使用collection接口。而会去使用它的两个子接口:List(允许重复)、Set(不允许重复)。
2.2 List接口
在List字接口中重点掌握以下方法:
方法 | 释义 |
---|---|
Public E get(int index) | 取得索引编号的内容 |
Public E set(int index,E element) | 修改指定索引编号的内容 |
Public ListIterator listIterator() | 为ListIterator接口实例化 |
- 而List本身属于接口,所以如果要想使用此接口进行操作,必须存在有子类,可以使用ArrayList子类是实现操作(还有一个Vector子类,多数选择ArrayList)。
2.2.1 子类:ArrayList
ArrayList类是List接口最为常用的一个子类。
范例:基本操作
public class TestDemo{
public static void main(String args[]){
List<String> all = new ArrayList<String>();
System.out.println("长度:"+all.size()+all.isEmpty());
all.add("wo");
all.add("de");
all.add("weilai");
all.add("bushimeng");
System.out.println("长度:"+all.size()+"是否为空:"+all.isEmpty());
// collection接口定义了size()方法可以取得集合长度
// List子接口扩充了一个get()方法,可以索引取得数据
for (int i = 0; i < all.size(); i++) {
String str = all.get(i);//取得索引数据
System.out.println(str);
}
}
}
演示发现,List集合之中保存的数据按照保存的顺序存放,而且允许数据重复,List子接口扩充有get()方法。Collection接口中无get()方法。
范例:集合中保存对象
class Book {
private String title;
private int price;
public Book(String title,int price) {
this.title = title;
this.price = price;
}
@override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
Book book = (Book) obj;
if (this.title.equals(book.title)&&this.price==book.price) {
return true;
}
return false;
}
@override
public String toString(){
return "书名:" + this.title + ",价格" + this.price + "\n";
}
}
public class TestDemo{
public static void main(String args[]) {
List<Book> all = new ArrayList<Book>();
all.add(new Book("java",23));
all.add(new Book("java",23));
all.add(new Book("java",23));
// 默认的操作方法是按照地址比较的,所以我们要覆写equals()方法
all.remove(new Book("java",23));
System.out.println(all);
}
}
2.2.2 旧的子类:vector
public class TestDemo{
public static void main(String args[]){
List<Book> all = new Vector<Book>();
all.add(new Book("java",23));
all.add(new Book("java",23));
all.add(new Book("java",23));
all.remove(new Book("java", 23));
System.out.println(all);
}
}
面试题:请解释Vector和ArrayList的区别
List接口学习总结
- List中的数据保存顺序就是数据的添加顺序,对数据的添加有精准的控制;
- List集合中可以保存重复的元素;
- List接口比Collection接口扩充了一个get()方法;
- List接口选择子类就使用ArrayList。
2.3 Set接口
在collection接口下又有一个比较常用的子接口set接口,set子接口并没有对collection接口进行大量的扩充,而是简单的继承了Collection接口,当然也没有get()方法.
Set接口有两个常用的子类:HashSet、TreeSet。
范例:观察HashSet子类的特点
public class TestDemo{
public static void main(String args[]){
Set<String> all = new HashSet<String>();
all.add("m");
all.add("a");
all.add("b");
all.add("c");
all.add("d");
all.add("d");
System.out.println(all);
}
}
}
- 通过代码演示可以发现,Set集合下没有重复的元素(这一点是Set接口的特征),同时发现里面保存的数据是无序排列的,即:HashSet子类的特征属于无序排列。
范例:使用TreeSet子类
public class TestDemo{
public static void main(String args[]){
Set<String> all = new TreeSet<String>();
all.add("m");
all.add("a");
all.add("b");
all.add("c");
all.add("d");
all.add("d");
System.out.println(all);
}
}
- 此时使用了TreeSet子类,没有重复数据,以及保存的内容自动排序。
2.4 关于数据排序的说明
集合就是一个动态的对象数组,那么如果要想为一组对象进行排序,在java里面必须要使用比较器,应该使用Comparable完成比较。在比较方法里面需要将这个类的所有属性都一起参与比较
class Book implements Comparable<Book> {
private String title;
private double price;
public Book(String title,double price) {
this.title = title;
this.price = price;
}
public String toString() {
return "书名:" + this.title + ",价格:" + this.price + "\n";
}
@Override
public int compareTo(Book o) {
if (this.price > o.price) {
return 1;
} else if (this.price < o.price) {
return -1;
}
return this.title.compareTo(o.title);
}
}
public class TestDemo {
public static void main(String args[]) {
Set<Book> all = new TreeSet<Book>();
all.add(new Book("java开发",79.8));
all.add(new Book("java开发",79.8)); // 全部重复
all.add(new Book("JSP开发",79.8)); // 价格重复
all.add(new Book("Android开发",89.8)); // 都不重复
System.out.println(all);
}
}
- 通过检测发现TreeSet主要是依靠Comparable接口中的ComparaTo()方法判断是否重复,如果返回是0,那么就是重复数据,不会被保存。
2.5 关于重复元素的说明
Comparable 接口只负责 TreeSet 子类进行重复元素的判断,它并不是真正的用于能够进行元素的验证的操作。现在只能够依靠Object类中的所提供的方法:
方法 | 释义 |
---|---|
public int hashCode() | 取得哈希码 |
public boolean equals(Object obj) | 对象比较 |
范例:(重写hashCode和equals方法)
class Book implements Comparable<Book> {
private String title;
private double price;
public Book(String title,double price) {
this.title = title;
this.price = price;
}
public String toString(){
return "书名:" + this.title + ",价格:" + this.price + "\n";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(price);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
@Override
public int compareTo(Book o) {
if(this.price > o.price){
return 1;
}else if(this.price < o.price){
return -1;
}
return this.title.compareTo(o.title);
}
}
public class TestDemo {
public static void main(String args[]) {
Set<Book> all = new HashSet<Book>();
all.add(new Book("java开发",79.8));
all.add(new Book("java开发",79.8));//全部重复
all.add(new Book("JSP开发",79.8));//价格重复
all.add(new Book("Android开发",89.8));//都不重复
System.out.println(all);
}
}
以后在非排序的情况下,只要是判断重复元素依靠的都是hashCode()与equals()方法。
2.6 集合输出
2.6.1 迭代输出:Iterator
一般集合的输出操作都会使用Iterator接口,观察Iterator接口的定义。
public interface Iterator<E> {
public boolean hasNext();
public E next();
}
Iterator本身是一个接口,如果想取得本接口实例化对象只能依靠Collection,Collection中定义一个操作方法: public Iterator iterator();
范例: 使用Iterator输出集合
public class Test{
public static void main(String args[]){
Set<String> all = new HashSet<String>();
all.add("呵呵");
all.add("和合伙");
Iterator<String> iter=all.iterator();
while(iter.hasNext()){
String str = iter.next();
System.out.println(str);
}
}
}
2.6.2 双向迭代:ListIterator
Iterator具备由前向后的输出,但是有的人想要实现由后向前可以使用Iterator的子接口ListIterator接口。
主要掌握两个方法:
方法 | 释义 |
---|---|
public boolean hasPrevious() | 判断是否有前一个元素 |
public E previous() | 取得前一个元素 |
ListIterator是专门为List子接口定义的输出接口,方法:public ListIterator listIterator。
范例:完成双向迭代
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Test{
public static void main(String args[]){
List<String> all = new ArrayList<String>();
all.add("a");
all.add("b");
all.add("c");
ListIterator<String> iter=all.listIterator();
while(iter.hasNext()){
String str=iter.next();
System.out.print(str+"、");
}
System.out.println("\n由后向前:");
while(iter.hasPrevious()){
String str = iter.previous();
System.out.print(str+"、");
}
}
}
- 如果想要实现由后向前的输出操作,一定要首先发生由前向后的输出。
2.6.3 foreach输出
public class Test{
public static void main(String args[]){
List<String> all = new ArrayList<String>();
all.add("a");
all.add("b");
all.add("c");
for(String str : all){
System.out.print(str);
}
}
}
2.6.4 Enumeration输出
Enumeration是与Vector类一起在JDK1.0的时候推出的输出接口,早期的Vector用Enumeration接口完成,此接口的定义如下:
方法 | 释义 |
---|---|
public boolean hasMoreElements() | 判断是否有下一个元素 |
public E nextElement() | 取得当前元素 |
– | – |
public Enumeration elements() | 取得Enumeration 操作对象 |
范例:Enumeration使用
public class Test{
public static void main(String args[]){
Vector<String> all = new Vector<String>();
all.add("a");
all.add("b");
all.add("c");
Enumeration<String> enu=all.elements();
while(enu.hasMoreElements()){
String str = enu.nextElement();
System.out.println(str);
}
}
}
2.7 Map 接口
Collection每一次都只会保存一个对象,而Map只要是负责保存一对对象的信息。
如果要现在要保存一对关联数据(key=value)的时候,那么使用Collection就不能满足要求,可以使用Map接口实现此类数据的保存,并且Map接口提供有根据key查找value的功能。
Map中定义的常用方法:
方法 | 释义 |
---|---|
public V put(K key,V value) | 普通 向集合中保存数据 |
public V get(Object key) | 普通 指定键所映射的值 |
public Set<Map.Entry<K,V>> | 普通 将Map集合转化为set集合 |
public Set keySet() | 取出全部的可以key |
在Map接口下有两个常用的子类:HashMap、Hashtable | |
代码示例: |
public class Test{
public static void main(String args[]){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("c", 17);
System.out.println(map);
}
}
通过以上的程序发现:
-
使用HashMap定义的Map集合是无序存放的;
-
如果出现重复的key会进行覆盖,新的value覆盖旧的
在HashMap接口里面提供有get()方法,这个方法的主要功能是根据key查找所需要的value。
public class Test{
public static void main(String args[]){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("c", 17);
map.put(null, 0); key 可以为空
System.out.println(map.get("c"));
System.out.println(map.get(null));//查询没有的key返回null,查询null返//回0
}
}
- 通过以上的验证可以发现,Map存放数据的目的是为了信息的查找,但是Collection存放数据是为了输出。
范例:取得Map的key
public class Test{
public static void main(String args[]) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("c", 17);
map.put(null, 0);
Set<String> set = map.keySet();
Iterator<String> ster = set.iterator();
while (ster.hasNext()) {
System.out.println(ster.next());
}
}
}
范例:使用Hashtable
public class Test{
public static void main(String args[]){
Map<String, Integer> map = new Hashtable<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("c", 17);
Set<String> set = map.keySet();
Iterator<String> ster=set.iterator();
while(ster.hasNext()){
System.out.println(ster.next());
}
}
}
- Hashtable 里面对于key和value的数据都不允许使用null。
2.8 关于Iterator输出的问题
之前一直强调集合的输出一定要使用Iterator完成,但是在Map接口里并没有定义可以返回Iterator接口对象的方法,分析Map和Collection集合保存数据的特点。
每当使用put()方法向Map集合里面保存一对数据的时候,实际上所有的数据都会被自动的封装为Map.Entry接口对象,那么来观察Map.Entry接口定义:
在这个接口里面定义两个操作:
- 取得key:public K getKey()
- 取得value:public V getValue()、
在Map集合中定义了一个将Map集合转换为Set集合的方法:
public Set<Map.Entry<K,V>> entrySet()
public static interface Map.Entry<K,V>
Map集合利用Iterator接口输出的步骤:
- 利用Map接口的entryset()方法将Map集合变为Set集合,里面的泛型是Map.Entry;
- 利用Set集合中的iterator()方法将Set集合进行Iterator输出;
- 每一次Iterator循环输出的都是Map.Entry接口对象,利用此对象进行key与value的取出。
范例:利用Iterator实现Map接口的输出
public class Test3 {
public static void main(String[] args) {
Map<String, Integer> map = new Hashtable<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("c", 17);
// 将Map集合变为Set集合,目的是为了使用iterator()方法
Set<Map.Entry<String, Integer>> set = map.entrySet();
Iterator<Map.Entry<String, Integer>> iter = set.iterator(); // 当然了也可以写成一句
while (iter.hasNext()) {
Map.Entry<String, Integer> me = iter.next();
System.out.println(me.getKey() + "=" + me.getValue());
}
}
}
遍历 Map使用的三种方式
public class Test3{
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值,通过 key 找 value
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种,通过键值对 对象 找key和value
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
}
}
相关文章
- Java 开发环境配置--eclipse工具进行java开发
- Java实现 蓝桥杯 算式最大值
- java实现平面点最小距离
- Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
- Java常用数据结构之Set之TreeSet
- 【JAVA】java中split以"." 、""、“|”分隔字符串
- 【JAVA】 04-Java中的多线程
- 【JAVA】 01-Java基础知识
- [Java] Map、Set、List、Queue、Stack的特点与用法
- java中List、Array、Map、Set等集合相互转换的最佳方法
- Java知识回顾 (18)Java 8、9、11的新特性
- Java 常用数据结构对象的实现原理 集合类 List Set Map 哪些线程安全 (美团面试题目)
- java中List、Array、Map、Set等集合相互转换的最佳方法
- atitit。gui 界面皮肤以及换肤总结 java .net c++
- Java — Map.keySet()、Map.put()、Map.get()【Map类、Set类】
- 蓝桥杯2018省赛——缩位求和(Java)
- Java Agent场景性能测试分析优化经验分享
- 【Java】java 性能监控及工具
- 【Java】一篇文章带你了解Collection接口、List集合、Set集合、Map集合