早在 Java 2 中之前,Java 就提供了特设类。比如:Dictionary, Vector, Stack, 和 Properties 这些类用来存储和操作对象组。虽然这些类都非常有用,但是传统数据结构缺少一个核心的,统一的主题。由于这个原因,使用 Vector 类的方式和使用 Properties 类的方式有着很大不同。
集合框架体系如图所示
除了集合,该框架也定义了几个 Map 接口和类。Map 里存储的是键/值对。尽管 Map 不是集合,但是它们完全整合在集合中。
了解了集合框架,下面就学习几个常用的集合具体实现类,实际开发中会更有帮助些!
ArrayList
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
import java.util.ArrayList; // 引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>(); // 初始化 E: 泛型数据类型,只能为引用数据类型。
objectName.add() // 添加元素
objectName.get() // 获取元素
objectName.set() // 修改元素
objectName.remove() // 删除元素,使用下标
objectName.size() // 获取数组元素个数
Collections.sort(objectName); // 数组排序
基本类型 | 引用类型 |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
LinkedList
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。
链表可分为单向链表和双向链表。
一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接。
一个双向链表有三个整数值: 数值、向后的节点链接、向前的节点链接。
什么时候使用链表?
以下情况使用 ArrayList :
- 频繁访问列表中的某一个元素。
- 只需要在列表末尾进行添加和删除元素操作。
以下情况使用 LinkedList :
- 你需要通过循环迭代来访问列表中的某些元素。
- 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
// 引入 LinkedList 类
import java.util.LinkedList;
LinkedList<E> list = new LinkedList<E>(); // 普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表
list.add() // 添加元素,默认添加接着添加
list.addFirst() // 添加到头部
list.addLast() // 添加到尾部
list.removeFirst() // 移除头部元素
list.removeLast() // 移除尾部元素
list.getFirst() // 获取头部元素
list.get() // 获取指定位置元素
HashSet
HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。无序,允许有Null值。
import java.util.HashSet; // 引入 HashSet 类
HashSet<String> sites = new HashSet<String>();
sites.add("Runoob"); // 重复的元素不会被添加
sites.remove("Taobao"); // 删除元素,删除成功返回 true,否则为 false
sites.contains("Taobao") // 判断元素是否存在
sites.size() // 计息大小
HashMap
HashMap 是一个无序散列表,它存储的内容是键值对(key-value)映射。
import java.util.HashMap; // 引入 HashMap 类
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
Sites.put(4, "Zhihu"); // 添加键值对
Sites.get(4); // 根据键获取对应的值
Sites.remove(4); // 根据键删除键值对
Sites.keySet(); // 获取HashMap的所有键Set
Sites.values(); // 获取HashMap的所有值
另外一种实例化方式:实例化时赋值
Iterator(迭代器)
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法
Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。
// 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
// 创建集合
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Zhihu");
// 获取迭代器
Iterator<String> it = sites.iterator(); // 实例化创建一个迭代器
// 输出集合中的第一个元素
System.out.println(it.next());
}
}
Object 类
Java Object 类是所有类的父类,也就是说 Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法。
序号 | 方法 & 描述 |
---|---|
1 | protected Object clone()创建并返回一个对象的拷贝 |
2 | boolean equals(Object obj)比较两个对象是否相等 |
3 | protected void finalize()当 GC (垃圾回收器)确定不存在对该对象的有更多引用时,由对象的垃圾回收器调用此方法。 |
4 | Class<?> getClass()获取对象的运行时对象的类 |
5 | int hashCode()获取对象的 hash 值 |
6 | void notify()唤醒在该对象上等待的某个线程 |
7 | void notifyAll()唤醒在该对象上等待的所有线程 |
8 | String toString()返回对象的字符串表示形式 |
9 | void wait()让当前线程进入等待状态。直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 |
10 | void wait(long timeout)让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数设置的timeout超时时间。 |
11 | void wait(long timeout, int nanos)与 wait(long timeout) 方法类似,多了一个 nanos 参数,这个参数表示额外时间(以纳秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 纳秒。。 |
泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
java 中泛型标记符:
- E – Element (在集合中使用,因为集合中存放的是元素)
- T – Type(Java 类)
- K – Key(键)
- V – Value(值)
- N – Number(数值类型)
- ? – 表示不确定的 java 类型
for ( E element : inputArray ){ # 遍历时不指定类型,由系统自动识别是什么类型的,偷懒操作,哈哈
System.out.printf( "%s ", element );
}
System.out.println();
序列化
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
类对象序列化的要求,必须满足两个条件:
该类必须实现 java.io.Serializable 接口。
该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。
public class Employee implements java.io.Serializable
{
public String name;
public String address;
public transient int SSN;
public int number;
public void mailCheck()
{
System.out.println("Mailing a check to " + name
+ " " + address);
}
}
序列化对象
注意: 当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名。
import java.io.*;
public class SerializeDemo
{
public static void main(String [] args)
{
Employee e = new Employee();
e.name = "Reyan Ali";
e.address = "Phokka Kuan, Ambehta Peer";
e.SSN = 11122333;
e.number = 101;
try
{
FileOutputStream fileOut =
new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
反序列化对象
下面的 DeserializeDemo 程序实例了反序列化,/tmp/employee.ser 存储了 Employee 对象。
import java.io.*;
public class DeserializeDemo
{
public static void main(String [] args)
{
Employee e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Employee...");
System.out.println("Name: " + e.name);
System.out.println("Address: " + e.address);
System.out.println("SSN: " + e.SSN);
System.out.println("Number: " + e.number);
}
}
以上程序编译运行结果如下所示: