JAVA学习笔记--初识容器类库
一、前言
JAVA中一切皆为对象,因而,持有对象显得尤为重要。
在JAVA中,我们可以通过创建一个对象的引用的方式来持有对象:
HoldingObject holding;
也可以创建一个对象数组来持有一组特定类型的对象:
HoldingObject holding = new HoldingObject[10];
但是,一个对象引用只能持有一个对象,一个对象数组只能持有固定数量且为某一特定类型的对象;然而,我们常常会遇到这种情况,在编写程序时,我们并不知道要创建多少个对象,甚至不知道要创建的对象的类型,因此,我们需要能够在任意时刻任意位置创建任意数量的对象,这是上面两种方法所做不到的。JAVA实用类库提供了一套相当完整的容器类来解决这个问题,其中的基本类型是List,Set,Queue,Map,我们称之为“容器”。
二、容器的分类
如上图所示,是一个简单的容器分类。可以看到,其实只有两种容器Collection和Map,而Collection又可以分为List,Set和Queue。它们各有两到三个实现,如:ArrayList,LinkedList是List的实现;HashMap,TreeMap是Map的实现。在上图中,常用的容器用黑色粗线框表示;点线框表示接口;实线框表示具体的类;空心箭头的点线表示一个特定的类实现了一个接口;实心箭头表示某个类可以生成箭头所指向类的对象。
1)Collection:
Collection保存一个独立的元素序列, 这些元素序列都服从一条或多条规则。Collection是一个接口,它表示一组对象,这些对象也被称为collection的元素,一些collection允许有重复元素,另一些则不允许。JDK不提供此接口的任何直接实现,它提供更具体的子接口实现(List,Set,Queue),此接口常用来传递collection,并在需要最大普遍性的地方操作这些collection。下面简单列出Collection的一些方法(截图自J2SE6_API):
a)List:必须按照插入的顺序保存元素
List是有序的collection,此接口的用户可以对列表中的每个元素的插入位置进行精确控制,用户可以根据元素的整数索引(在列表中的位置)来访问元素,并搜索列表中的元素。List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和移除元素。List允许在它被创建之后添加元素、移除元素,或者自我调整尺寸,这正是它的价值所在:一种可修改的序列。有两种类型的List实现:
ArrayList:随机访问元素时比较快,但是插入和移除元素时比较慢;
ArrayList有三种构造方法:
ArrayList(); // 构造一个初始容量为10的空列表 ArrayList(int x); // 构造一个初始容量为x的空列表 ArrayList(Collection<? extends E> c); // 构造一个包含指定collection的元素的列表,这些元素是按照collection的迭代器返回它们的顺序排列的
下面用一个简单的例子来介绍一下ArrayList的基本操作:
package com.tongye.holding; import java.util.ArrayList;
import java.util.List;
import java.util.Random; public class HoldObject {
public static void main(String[] args){
Random rand = new Random(47);
Circle circle = new Circle();
Square square = new Square();
Triangle triangle = new Triangle();
Rectangle rectangle = new Rectangle(); // 创建List实例
List<Integer> list1 = new ArrayList<Integer>(); // 创建一个只能存储int类型对象的列表
List<Shape> list2 = new ArrayList<Shape>(); // 创建一个只能存储Shape类型对象的列表
List list3 = new ArrayList(4); // 创建一个初始容量为4的列表,没有指定存储的类型 // 向列表list1中添加元素
for(int i = 0;i < 10;i++)
list1.add(rand.nextInt(20)); // add(E e)方法,将指定元素添加到此列表的尾部
for(Integer i : list1) // 所有的collection都可以用foreach进行遍历
System.out.print(i + " ");
System.out.println(""); // 用subList方法截取一部分list1的视图
List<Integer> list4 = list1.subList(3, 8); // subList(int fromIndex,int toIndex),返回列表中
// 从fromIndex(包括)到toIndex(不包括)之间的部分视图
for(Integer i : list4)
System.out.print(i + " ");
System.out.println(""); // 向列表list2中添加元素
list2.add(circle); // 向列表中添加对象
list2.add(square);
list2.add(triangle);
list2.add(1,rectangle); // add(int index,E e)方法,向列表的指定位置插入指定元素
for(Shape i : list2) // 所有的collection都可以用foreach进行遍历
System.out.println(i);
System.out.println(list2.isEmpty()); // isEmpty()方法,检查列表中是否有元素,没有元素则返回true
System.out.println(list2.contains(circle)); // contains()方法用于检查列表中是否含有指定元素,有则返回true
System.out.println(list2.indexOf(square)); // indexOf()方法,用于返回元素在列表中的索引号
list2.get(1).showShape();
list2.remove(rectangle); // remove(Object o)方法,删除列表中首次出现的指定元素
list2.get(1).showShape();
list2.remove(1);
list2.get(1).showShape(); // remove(int index)方法,删除列表中指定索引处的元素 // 向list3中添加元素
list3.add(100);
list3.add("向列表中添加一个字符串");
list3.add(rectangle);
list3.add(1.048596);
list3.add("容量自动增长");
for(int i = 0;i < 5;i++)
System.out.println(list3.get(i));
}
} class Shape{
public void showShape(){
System.out.println("Shape类");
}
} class Circle extends Shape{
public void showShape(){
System.out.println("Circle类");
}
} class Square extends Shape{
public void showShape(){
System.out.println("Square类");
}
} class Triangle extends Shape{
public void showShape(){
System.out.println("Triangle类");
}
} class Rectangle extends Shape{
public void showShape(){
System.out.println("Rectangle类");
}
}
ArrayList Code
LinkedList:通过代价较低的在List中间进行的插入和删除操作,提供了优化的顺序访问。LinkedList也和ArrayList一样实现了基本的List接口,但是它在执行某些操作的时候比ArrayList更高效(在List中插入和删除),但在随机访问操作方面却要逊色一些。如果我们需要使用LinkedList,只需要在程序中修改List的实现即可,这也是使用接口的好处:
List<Integer> list = new LinkedList<Integer>(); // 用LinkedList来实现List
b)Set:不能有重复元素
Set是一个不包含重复元素的collection,更确切地讲,Set不包含满足 e1.equals(e2) 的元素对 e1和e2,并且最多包含一个null元素;Set具有和Collection完全一样的接口,因此没有任何额外的功能,实际上Set就是Collection,只是行为不同;它有三个实现:HashSet、TreeSet、LinkedHashSet.
①、HashSet:
HashSet是基于HashMap的一个set实现,它不保证set的迭代顺序,特别是不保证该顺序永久不变;
HashSet允许使用null元素;
HashSet为基本操作提供了稳定性能(add,remove,contains,size);
HashSet进行迭代所需的时间与HashSet实例的大小(元素的数量)和底层HashMap实例的“容量”成比例,因此如果迭代性能很重要,则不要讲初始容量设置得太高(或将加载因子设置的太低);
HashSet是不同步的,在多线程中同时访问一个HashSet时,需要使用同步语句来加锁,可以使用 Collection.synchronizedSet方法来包装set,最好在创建的时候完成这一步,一面对set进行意外的不同步访问: Set s = Collections.synchronizedSet(new HashSet( ));
HashSet的iterator方法返回的迭代器是快速失败的:在创建迭代器后,如果对set进行修改,除非通过迭代器自身的remove方法,否则在任何时间以任何方式对其进行修改,Iteractor都将抛出异常。
HashSet有四种构造方法:
HashSet(); // 创建一个空的set,其底层HashMap实例的默认初始容量是16,加载因子是0.75 HashSet(Collection<? extends E> c); // 创建一个包含指定collection中的元素的新set HashSet(int intialCapacity); // 创建一个具有指定初始容量和默认加载因子的set HashSet(int intialCapacity,float loadFactor); // 创建一个具有指定初始容量和加载因子的set
②、TreeSet:
TreeSet是基于TreeMap的一个set实现;
TreeSet为基本操作提供受保证的时间开销(add,remove,contains);
TreeSet使用元素的自然顺序对元素进行排序,或根据创建元素时提供的Comparator进行排序,具体取决于使用的构造方法;
TreeSet是不同步的;
TreeSet的iterator方法返回的迭代器是快速失败的;
TreeSet有四种构造方法:
TreeSet(); // 创建一个新的空set,该set根据其元素的自然顺序进行排序 TreeSet(Collection<? extends E> c); // 创建一个包含指定collection元素的新的TreeSet,它按照其元素的自然顺序进行排序 TreeSet(Compartor<? super E> compartor); // 创建一个新的空的TreeSet,它根据指定的比较器进行排序
TreeSet(SortedSet<E> s); // 创建一个与指定有序set具有相同映射关系和相同排序的新TreeSet
③、LinkedHashSet:
LinkedHashSet是具有可预知迭代顺序的set接口的哈希表和链接列表实现;
LinkedHashSet定义了迭代顺序,即按照元素插入到set中的顺序进行迭代,插入顺序不受在set中重新插入的元素的影响;
LinkedHashSet迭代所需时间与set的大小成正比而与容量无关;
LinkedHashSet提供了所有可选的set操作,并且允许null元素;可以为基本操作提供稳定的性能;不同步;迭代器是快速失败的
其构造方法与HashSet类似。
下面用一个简单的例子介绍一下Set的基本操作:
package com.tongye.holding; import java.util.Random;
import java.util.Set;
import java.util.HashSet;
import java.util.TreeSet; public class SetExample {
public static void main(String[] args){
Random rand = new Random(47);
Set<Integer> hashSetInt = new HashSet<Integer>();
for(int i = 0;i < 100;i++)
hashSetInt.add(rand.nextInt(20));
System.out.println(hashSetInt); Set<Integer> treeSetInt = new TreeSet<Integer>();
for(int i = 0;i < 100;i++)
treeSetInt.add(rand.nextInt(20));
System.out.println(treeSetInt);
}
}
Set Code
注:实际上,我在eclipse上运行上述代码,发现无论是HashSet还是TreeSet,输出的元素都是按自然顺序排列的,查阅资料后发现可能是JDK版本的原因,JDK8中HashMap的实现有了一些变化,这些新特性导致了HashSet输入整型数据时会按照自然顺序进行排列。
c)Queue:按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)
Queue(队列)是一个典型的先进先出的容器,它有两个实现 LinkedList以及PriorityQueue。LinkedList提供了方法以支持队列的行为,并且实现了Queue接口;PriorityQueue(优先级队列)声明下一个弹出元素是最需要的元素(具有最高优先级)。
2)Map:保存一组成对的“键值对”对象,允许使用键来查找值
Map可用于将一个对象映射到其他对象上。Map接口提供三种collection视图,允许以键集、值集或键-值映射关系集的形式查看某个映射的关系。映射顺序为迭代器在映射collection视图上返回其元素的顺序。它有两个实现:HashMap和TreeMap。
HashMap:
基于哈希表的Map实现,此实现提供所有可选的映射操作,并允许使用null值和null键;不保证映射的顺序,特别是不保证该顺序恒久不变。
构造方法:
HashMap(); // 创建一个具有默认初始容量(16)和默认加载因子(0.75)的空的HashMap HashMap(int initialCapacity); // 创建一个指定初始容量和默认加载因子的空的HashMap HashMap(int initialCapacity,float loadFactor); // 创建一个指定初始容量和指定加载因子的空的HashMap HashMap(Map<? extends K,? extends V> m); // 创建一个映射关系与指定Map相同的新的HashMap
TreeMap:
基于红黑树的Map实现,该映射根据其键的自然顺序进行排序,或根据创建映射时提供的Compartor进行排序,具体取决于使用的构造方法。
TreeMap(); //使用键的自然顺序创建一个新的空的树映射 TreeMap(Compartor<? super K> compartor); // 构造一个新的空的树映射,该映射根据给定比较器进行排序 TreeMap(Map<? extends K,? extends V> m); // 构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序进行排序 TreeMap(SortedMap<K,? extends V> m); // 构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射
下面用一个简单的例子简单介绍一下Map一些用法:
package com.tongye.holding; import java.util.HashMap;
import java.util.Map;
import java.util.Random; public class MapExample {
public static void main(String[] args){
Random rand = new Random(47);
Map<Integer,Integer> mapInt = new HashMap<Integer,Integer>(); // 创建一个空的新的HashMap
for(int i = 0; i < 10000; i++){
Integer key = rand.nextInt(20);
Integer value = mapInt.get(key); // 返回该键所映射的值,如果该键还没有任何映射关系,则返回null
mapInt.put(key, value == null? 1 : value + 1); // 在此映射中关联指定值与指定键
}
System.out.println(mapInt);
}
}
Map Code
JAVA学习笔记--初识容器类库的更多相关文章
- Java 学习笔记(10)——容器
之前学习了java中从语法到常用类的部分.在编程中有这样一类需求,就是要保存批量的相同数据类型.针对这种需求一般都是使用容器来存储.之前说过Java中的数组,但是数组不能改变长度.Java中提供了另一 ...
- 5.10(java学习笔记)容器的同步控制与只读设置
1.容器的同步控制 像我们平常使用的容器有些是不同步的即线程不安全,例如HashMap等,在多线程时可能出现并发问题. 而有些容器又是同步的,例如Hashtable. 有些时候我们需要将这些不同步的容 ...
- Java学习笔记--常用容器
容器 1. 出现原因 解决程序运行时需要创建新对象,在程序运行前不知道运行的所需的对象数量甚至是类型的问题. Java中提供了一套集合类来解决这些问题包括:List.Set.Queue.Map 2. ...
- Java学习笔记心得——初识Java
初识Java 拿到这本厚厚的<Java学习笔记>,翻开目录:Java平台概论.从JDK到TDE.认识对象.封装.继承与多态...看着这些似懂非懂的术语名词,心里怀着些好奇与担忧,就这样我开 ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- Java学习笔记4
Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
- 0032 Java学习笔记-类加载机制-初步
JVM虚拟机 Java虚拟机有自己完善的硬件架构(处理器.堆栈.寄存器等)和指令系统 Java虚拟机是一种能运行Java bytecode的虚拟机 JVM并非专属于Java语言,只要生成的编译文件能匹 ...
- Java学习笔记--Swing用户界面组件
很多与AWT类似. 事件处理参考:Java学习笔记--AWT事件处理 1.设计模式: 模型:存储内容视图:显示内容控制器:处理用户输入· 2. 文本输入常用组件 2.1 文本域: JLabel lab ...
随机推荐
- 字符型设备驱动程序-first-printf以及点亮LED灯(一)
学习使用 Linux 的 字符型设备驱动 来 进行 . 学习地址:http://edu.51cto.com/lesson/id-25710.html 第一步: 首先写 三个函数 ,2017年5月17 ...
- vue中监听页面滚动和监听某元素滚动
①监听页面滚动 在生命周期mounted中进行监听滚动: mounted () { window.addEventListener('scroll', this.scrollToTop) }, 在方法 ...
- Oracle 安全性一
创建和管理数据库用户账户 用户账户属性 用户账户拥有很多在创建账户时定义的属性.这些属性将应用于连接到账户的会话,在会话运行期间,DBA或会话可以更改其中一些属性. 用户名 身份验证方法 默认表空间 ...
- iOS中怎么判断可变和不可变的坑(更正版)
iOS中怎么判断可变和不可变的坑 怎么判断NSString和NSMutableString呢 看题 BOOL result = [" isKindOfClass:[NSMutableStri ...
- iOS 第三方库、插件、知名博客总结
iOS 第三方库.插件.知名博客总结 用到的组件 1.通过CocoaPods安装 项目名称 项目信息 AFNetworking 网络请求组件 FMDB 本地数据库组件 SDWebImage 多个缩略图 ...
- php无限极分类处理
/** * 无限极分类处理(通过递归方式实现) * @param $section 原始数据Array * @param $html 界面显示前缀,比如 |- * @param $spear 分级中所 ...
- linux下安装protobuf及cmake编译
一.protobuf 安装 protobuf版本:2.6.1 下载地址:https://github.com/google/protobuf/archive/v2.6.1.zip 解压之后进入目录 修 ...
- MySQL----MySQL数据库入门----第五章 多表操作
5.1 外键 比如说有两个数据表,分别是学生信息表student和年级表grade.在student表中有存储学生年级的字段gid(外键),在grade表也有存储学生年级的字段id(主键),stude ...
- JavaScript入门学习(2)--进度条
<html> <style type="text/css"> #bar{width:0px; height:20px; background:#ee00ff ...
- Zeta--S3 Linux抓取一帧YUV图像后使用硬件编码器编码成H.264
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h&g ...