集合
Java中的集合,指一系列存储数据的接口和类,可以解决复杂的数据存储问题.
导包:import java.util.*;
简化的集合框架图:
集合框架图:
这里只终结经常用的ArrayList,LinkedList、HashSet以及HashMap,有的内容会以仿写源码的方式来实现一些经常用到的方法
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
- 接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
- 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
- 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现
List
ArrayList
类似于数组但是ArrayList的长度是动态增加的,所以也被称为动态数组
这里我们通过仿写源码的方法来了解下是怎么实现的
在eclipse中按F3可以查看相关的源码
import java.util.List;
//模仿标准库提供的 ArrayList
class ArrayList_02 < E > {//泛型类
// 默认容量
private static final int DEFAULT_CAPACITY = 10;
// 存放数据的空间
transient Object[] elementData;
// 实际存放元素的个数
private int size;
// 默认构造
public ArrayList_02() {
elementData = new Object[DEFAULT_CAPACITY];
}
// 有参构造
public ArrayList_02( int capacity ) {
if ( capacity < 0 ) {
throw new RuntimeException("容器的容量不能为负数!");
}
else if ( capacity == 0 ) {
elementData = new Object[DEFAULT_CAPACITY];
}
else {
elementData = new Object[capacity];
}
}
// 在末尾添加一个元素
public void add( E element ) {//泛型方法
// 什么情况下需要扩容
if ( size == elementData.length ) {
// 如何扩容
// 1. 在一个新的地方重新开辟一块内存空间,大小为原来的 1.5倍
Object[] newArray = new Object[ elementData.length + (elementData.length>>1) ];
// 2. 将原来的容器的内容 全部按顺序 复制到新容器中
System.arraycopy( elementData, 0, newArray, 0, elementData.length);
// 3. 将新的空间交给 elementData 来引用
elementData = newArray;
}
elementData[size++] = element;
}
// toString 重写
@Override
public String toString() {
StringBuffer strbuf = new StringBuffer();
// [1, 2, 3]
strbuf.append("[");
if(size!=0) {
for ( int i=0; i<size; i++ ) {
strbuf.append( elementData[i] + ", " );
}
strbuf.setCharAt(strbuf.length()-2, ']');
}else {
strbuf.append("]");
}
return strbuf.toString();
}
// get
public E get( int index ) {
// 判断 index 是否在 容器的长度范围内
if ( index < 0 || index >= size ) {
// 不合法,需要抛异常
throw new RuntimeException( "需要访问的 ["+ index +"] 索引(下标)访问超出容器的实际长度!" );
}
return (E)elementData[index];
}
// set
public void set( int index, E element ) {
// 判断 index 是否在 容器的长度范围内
if ( index < 0 || index >= size ) {
// 不合法,需要抛异常
throw new RuntimeException( "需要访问的 ["+ index +"] 索引(下标)访问超出容器的实际长度!" );
}
elementData[index] = element;
}
// 按位置
public void remove( int index ) {
// 判断 index 是否在 容器的长度范围内
if ( index < 0 || index >= size ) {
// 不合法,需要抛异常
throw new RuntimeException( "需要访问的 ["+ index +"] 索引(下标)访问超出容器的实际长度!" );
}
// 计算后面有多少的个元素需要向前挪动一格
int needmovenum = elementData.length-index-1;
// 当 删除的位置不是最后一个的时候
if ( needmovenum > 0 ) {
System.arraycopy(elementData, index+1, elementData, index, needmovenum);
}
// 将原容器最后一个位置上的元素 置空
elementData[--size] = null;
}
// 按内容
public void remove( E element ) {
// 遍历容器找到和 element 一样的元素
for ( int i=0; i<size; i++ ) {
// if ( element.equals( get(i) )) {
if ( element.equals( elementData[i] )) {
// 将该位置上的元素 删除
remove(i);
return;
}
}
throw new RuntimeException(" 需要删除的内容,不在当前容器中!");
}
//获取长度
public int size() {
return size;
}
//判断是否为空。空则返回true,否则返回false
public boolean isempty() {
// TODO Auto-generated method stub
if(size<=0)
return true;
else
return false;
}
//清空集合
public void clear() {
// TODO Auto-generated method stub
for ( int i=0; i<size; i++ ) {
elementData[size] = null;
}
size=0;
}
//判断是否包含某个元素
public boolean contains(String str) {
for ( int i=0; i<size; i++ ) {
if ( str.equals( elementData[i] )) {
return true;
}
}
return false;
}
}
public class Code_004 {
public static void main(String[] args) {
ArrayList_02 arr_02 = new ArrayList_02(5);
arr_02.add("qwer");
arr_02.add("asdw");
arr_02.add("qwer_01");
arr_02.add("asdw_01");
arr_02.add("qwer_02");
arr_02.add("asdw_02");
// System.out.println(arr_02);
// arr_02.set(7, "777");
// arr_02.remove(6);
// arr_02.remove("777");
// arr_02.remove(5);
//arr_02.remove("qwer");
System.out.println(arr_02.contains("qwer"));
System.out.println(arr_02.size());
System.out.println(arr_02.isempty());
System.out.println(arr_02);
arr_02.clear();
System.out.println(arr_02);
}
}
遍历ArrayList的方法
import java.util.*;
public class ListTraversal {
public static void main(String[] args) {
m010Traversal();
m020线程安全版();
}
private static void m010Traversal() {
System.out.println("=====遍历");
List<String> lst = new ArrayList<String>();
lst.add("西藏");
lst.add("拉萨");
lst.add("土耳其");
// (1)
for (int i = 0; i < lst.size(); i++) {
System.out.println("for遍历集合:" + lst.get(i));
}
// (2)
for (String s : lst) {
System.out.println("foreach遍历集合:" + s);
}
// (3)Iterator,迭代器。用于遍历(迭代访问)集合中的元素
Iterator<String> it = lst.iterator();
while (it.hasNext()) {
System.out.println("Iterator遍历:" + it.next());
}
// (4)Java 8:调用forEach()方法遍历集合
lst.forEach(s -> System.out.println("Lambda表达式遍历集合:" + s));
}
// API文档上说ArrayList不是同步的,即多线程环境下不安全
// Collections.synchronizedList(...)将其转为线程安全的列表
private static void m020线程安全版() {
System.out.println("=====线程安全版");
List<String> lst = new ArrayList<String>();
lst.add("西藏");
lst.add("拉萨");
lst.add("土耳其");
// 解决线程安全问题
List<String> synList = Collections.synchronizedList(lst);
for (String s : synList) {
System.out.println("foreach遍历集合:" + s);
}
}
}
LinkedList
LinkedList原理图示
LinkedList特有的方法:
import java.util.LinkedList;
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<String> link = new LinkedList<String>();
// addFirst:头部添加数据
link.addFirst("A");
link.addFirst("B");
link.addFirst("C");
link.removeFirst();
System.out.println(link);
// addLast:尾部添加数据
link.addLast("A");
link.addLast("B");
link.addLast("C");
link.removeLast();
System.out.println(link);
link.clear();// 清空
// push:将元素推入栈,等效于addFirst()
link.push("A");
link.push("B");
link.push("C");
// pop:出栈,调用的是removeFirst()
link.pop();
System.out.println("栈" + link);
link.clear();// 清空
// 将指定元素添加到此列表的末尾(最后一个元素)。
// offer:入队列:调用的是add方法,add又调用linkLast,和addLast 一样
link.offer("A");
link.offer("B");
link.offer("C");
// poll:出队列:调用的是removeFirst()
link.poll();
System.out.println("队列" + link);
}
}
在终端的结果
[B, A]
[B, A, A, B]
栈[B, A]
队列[B, C]
Hash表
Java8之前:Hash表使用数组+链表
Java8之后加入了红黑树,查询速度加快
HashSet
没有重复数据,数据不按存入顺序。
由Hash表结构(实际上是一个HashMap实例)支持。
不支持set的迭代顺序,不保证顺序恒久不变。
Hash表结构查询速度快。
HashSet的遍历
public static void main(String[] args) {
Set s = new HashSet();
// 存
s.add("a");
s.add("a"); // 只会显示一个 a
s.add("sss");
s.add(1);
s.add(2);
s.add("你好");
s.add(true);
System.out.println(s);
/**
* set 没有所以你的概念,因此只能使用迭代器 或者 增加的 for 循环来遍历
* */
// 取
System.out.println("=============== iterator 迭代 ===========");
Iterator it = s.iterator();
// 迭代过程不可以移除数据
while (it.hasNext()) { // 查看是否有下一个
System.out.println(it.next());
}
System.out.println("=========== 增强的 for 循环 ==============");
// foreach (迭代的过程不能移除元素)
for (Object o: s) {
System.out.println(o);
}
System.out.println("=========== Lambda表达式 ==============");
// (3)*Java 8新增遍历方法
s.forEach(elm -> System.out.println("Lambda:" + elm));
// 移除
s.remove("aaa");
}
HashMap
存储K-V,使用key来区分
import java.util.*;
public class TestHashMap {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
// 新k返回null,旧k返回旧v
String put = map.put(1, "A");
System.out.println("之前没有此K的V:" + put);
put = map.put(1, "B");
System.out.println("之前有同K的V:" + put);
System.out.println(map);
// get:有k返回v,无k返回null
String v = map.get(2);
System.out.println(v);
v = map.get(1);
System.out.println(v);
// containsKey/containsValue
boolean containsKey = map.containsKey(2);
boolean containsValue = map.containsValue("B");
// remove:删k返回v;删无可删,返回null
String remove = map.remove(2);
System.out.println(remove);
remove = map.remove(1);
System.out.println(remove);
}
}
HashMap的遍历
import java.util.*;
public class TestMap1Hash {
public static void main(String[] args) {
Map<String, String> _map = new HashMap<String, String>();
_map.put("1", "悟空");
_map.put(null, "白龙");
_map.put("2", "悟能");
_map.put("3", "悟净");
System.out.println("------foreach语法遍历map(输出K-V)------ ");
for (String _key : _map.keySet()) {
System.out.print("key = " + _key);
System.out.println(" value = " + _map.get(_key));
}
System.out.println("------Java 8.forEach:Lambda------");
_map.forEach((k, v) -> System.out.println(k + ":" + v));
System.out.println("------使用迭代器迭代map(输出V)------");
// 1.获取值的Collection
Collection<String> _values = _map.values();
// 2.通过Collection获得迭代器
Iterator<String> it = _values.iterator();
// 3.输出值
while (it.hasNext()) {
String next = it.next();
System.out.println(next);
}
System.out.println("-----Map.Entry<K,V>-----");
// Map.Entry<K,V>是Map的内部接口,称为映射项(键-值对)
Set<Map.Entry<String,String>> entrySet = _map.entrySet();
System.out.println("=====Map.Entry<K,V>:for循环=====");
for (Map.Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() + ":" +
entry.getValue());
}
System.out.println("=====Map.Entry<K,V>:迭代器=====");
Iterator<Map.Entry<String, String>> iterator =
entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
System.out.println(next.getKey() + ":" +
next.getValue());
}
}
}
泛型
泛型类和泛型方法在ArrayList中都有就不再举例
泛型接口
public interface Plane<T> {
void getP();
void setP(T t);
}
static class WarmPlane<T> implements Plane<T>{
String fun = "运输";
@Override
public void getP() {
System.out.println(fun);
}
@Override
public void setP(T t) {
fun += "-----" + (String) t;
}
}
public static void main(String[] args) {
WarmPlane wl=new WarmPlane();
wl.getP();
wl.setP("预警");
wl.getP();
}