集合框架总图:
一、ArrayList
为什么要使用?
存放多个对象也可以使用数组,但是定义数组有局限性,例如先声明个长度为20的数组,如果存10个就浪费了空间,存25个又不够。所以引入容器,ArrayList就是一种常见的容器,容器的容量会随着存放的对象自动增多。
常用方法
例子:
public class ArrayListTest {
public static void main(String[] args) {
//泛型,list只能存string类型
//下面这样写可以存各种类型
//ArrayList list1 = new ArrayList();
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
System.out.println(list);
System.out.println("之前的长度:"+list.size());
list.add("ddd");
System.out.println("新添加一个元素后的长度:"+list.size());
System.out.println(list);
//contains判断容器中是否有某元素
System.out.println("是否存在aaa:"+list.contains("aaa"));
//get获得指定位置的元素
System.out.println("第2个元素是:"+list.get(1));
//set替换某位置的元素
System.out.println("拿AAA替换第一个元素:"+list.set(0, "AAA"));
System.out.println(list);
//转化为数组,如果要转换为一个string数组,
//那么需要传递一个string数组类型的对象给toArray(),
//这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组
String []arr = new String[list.size()];
arr=(String[]) list.toArray(new String[] {});
for(String str:arr) {
System.out.println("转化成数组:"+str);
}
//清空list
list.clear();
System.out.println(list);
}
}
泛型
不指定泛型的容器,可以存放任何类型的元素
指定了泛型的容器,只能存放指定类型的元素以及其子类,如上面代码的 ArrayList<String> list,只能存放String类型
三种遍历集合的方法
使用for循环
方便操作集合中相关元素
使用迭代器iterator
增强型for循环
使用增强型for循环可以非常方便的遍历ArrayList中的元素,这是很多开发人员的首选
不过增强型for循环也有不足:
无法用来进行ArrayList的初始化
无法得知当前是第几个元素了,当需要只打印单数元素的时候,就做不到了。 必须再自定下标变量。
代码:
public class Test {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
for(int i=0;i<10;i++) {
al.add(i);
}
System.out.println("----------for循环遍历------------");
for(int i=0;i<al.size();i++) {
/*for循环遍历的好处,可以操作相关元素
* if((i+1)%8==0) {
al.remove(i);
continue;
}*/
System.out.print(al.get(i)+",");
}
System.out.println();
System.out.println("----------迭代器遍历------------");
Iterator<Integer> it = al.iterator();
while(it.hasNext()) {
System.out.print(it.next()+",");
}
System.out.println();
System.out.println("----------foreach循环遍历------------");
for(Integer i:al) {
System.out.print(i+",");
}
}
}
二、LinkedList
LinkedList也实现了List接口,像add(),get()这些List的方法也可以使用。
Deque
特别的是 它实现了双向链表Deque,可以很方便的在头和尾进行操作;
常用方法:
addFirst()在最前面插入元素,addLast()在最后面插入元素,
getFirst(),getLast查看头部和尾部元素,
removeFirst(),removeLast()移除头部尾部元素
Queue
还实现了Queue(队列)接口,队列的特点是先进先出(FIFO)
常用方法:
offer() 在最后面添加元素
peek()查看第一个元素
pool()取出第一个元素
代码
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Integer> ll = new LinkedList<Integer>();
//双向链表deque
Deque<Integer> d = new LinkedList<Integer>();
//队列queue
Queue<Integer> q = new LinkedList<Integer>();
//初始化
for(int i=1;i<10;i++) {
ll.add(i);
d.add(i);
q.add(i);
}
/*
* Deque的相关方法
*
* addLast
* getFirst
* removeFirst
*
*/
System.out.println("deque初始值"+d);
//尾部添加10
d.addLast(10);
System.out.println("尾部添加:"+d);
//头部添加0
d.addFirst(0);
System.out.println("头部添加:"+d);
//查看第一个
System.out.println("查看头部:"+d.getFirst());
//取出最后一个
d.removeLast();
System.out.println("取出最后一个:"+d);
/*
* Queue队列的相关方法
* offer放置队尾
* poll取出队列第一个元素
* peek查看队列第一个元素
*/
System.out.println("queue初始值:"+q);
q.offer(10);
System.out.println("队尾添加后:"+q);
q.poll();
System.out.println("使用poll去掉队首:"+q);
System.out.println("使用peek查看队首:"+q.peek());
结果:
stack
stack栈是先进后出(FILO),利用Deque实现自定义Stack
先定义接口Stack
public interface Stack {
//把元素推入到最后位置
public void push(Integer i);
//把最后一个元素取出来
public Integer pull();
//查看最后一个元素
public Integer peek();
}
自定义MyStack实现接口
public class Mystack implements Stack {
Deque<Integer> dq = new LinkedList<Integer>();
public void push(Integer i) {
// 入栈,到最底部
dq.addLast(i);
}
public Integer pull() {
// 取出最后一个元素
return dq.removeLast();
}
public Integer peek() {
// 查看最后一个元素
return dq.getFirst();
}
}
三、二叉树
建立二叉树:基本思想 小的在左边,大的在右边
public class Node {
//左子节点
public Node leftNode;
//右子节点
public Node rightNode;
//值
public Object value;
public void add(Object o) {
//如果当前节点值为空
if(value==null) {
value=o;
}
else {//值小于等于根的值放入左节点
if((int)o<=(int)value) {
if(leftNode==null) {
leftNode = new Node();}
leftNode.add(o);
}else {//值大于根的值
if(rightNode==null)
{rightNode = new Node();}
rightNode.add(o);
}
}
}
}
二叉树的遍历:前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
接下来是中序遍历,顺便还能排序,这就是二叉树排序
public List<Object> values() {
//中序遍历二叉树
List<Object> al = new ArrayList<>();
//左节点
if(leftNode!=null)
al.addAll(leftNode.values());
//当前节点
al.add(value);
//右节点
if(rightNode!=null)
al.addAll(rightNode.values());
return al;
}
四、HashMap
HashMap的存储方式是键值对的方式,键不能重复,值可以重复
public class HashMapTest {
public static void main(String[] args) {
HashMap<String, String> hm = new HashMap<>();
hm.put("name", "tom");
hm.put("age", "18");
hm.put("sex", "man");
System.out.println(hm.get("name"));
}
}
3种遍历方式,分别使用foreach和迭代器遍历
package com.yyt.pojo;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicStampedReference;
import javax.activation.MailcapCommandMap;
public class YeYangTao {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("001", "yyt1");
map.put("002", "yyt2");
map.put("003", "yyt3");
//ketSet遍历 foreach
for(Object o:map.keySet()) {
System.out.println(o);
}
//ketSet遍历 迭代器
Iterator it1 = map.keySet().iterator();
while(it1.hasNext()) {
System.out.println(it1.next());
}
//values foreach
for(Object o:map.values()) {
System.out.println(o);
}
//values 迭代器
Iterator it2 = map.values().iterator();
while (it2.hasNext()) {
System.out.println(it2.next());
}
//entry foreach
Set<Entry<String, String>> entry = map.entrySet();
for(Entry<String, String> e:entry) {
System.out.println(e.getKey()+","+e.getValue());
}
//entry 迭代器
Iterator<Entry<String, String>> it = map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<String, String> entry1 = it.next();
System.out.println(entry1.getKey()+","+entry1.getValue());
}
}
}
五、HashSet
无序,不可重复。其实它就是HashMap中的key。
它没有顺序,不能通过get()来获取元素
所以遍历用增强型for循环和Iterator迭代器
接下来用HashSet来解决一个问题:
问题:
创建一个长度是100的字符串数组
使用长度是2的随机字符填充该字符串数组
统计这个字符串数组里重复的字符串有多少种并输出重复值
思路:定义两个HashSet,利用第一个插入随机字符串数组,但是HashSet不允许重复,所以第二次遇到重复的则会插入失败,用第二个HashSet保存插入失败的元素,最后只需要统计第二个HashSet的长度和其中元素便找到了有多少种重复和重复值是什么。
代码:
public class HashSetTest {
public static void main(String[] args) {
//获取100个长度为2的随机字符串
String s[] = new String[100];
for(int i=0;i<s.length;i++) {
s[i] = randomStr(2);
}
System.out.println("初始化字符串数组为:");
for(int i=0;i<s.length;i++) {
System.out.print(s[i] +" ");
if(i%10==9)
System.out.println();
}
HashSet<String> repeat =new HashSet<String>();
HashSet<String> sets =new HashSet<String>();
for(String str:s) {
if(!sets.add(str)) {//当之前有重复值的时候,第二次会插入失败
repeat.add(str);//将插入失败的值保存,也就是重复值
}
}
System.out.println("重复的有"+repeat.size()+"个");
for(String str:repeat) {
System.out.println(str);
}
}
//获取随机字符串
public static String randomStr(int length) {
Random r = new Random();
int i;
String s = "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM1234567890";
char sa[]=new char[length];
for(int j=0;j<length;j++) {
//26个大写字母,26个小写字母,10位数字
i = r.nextInt(26+26+10-1);
sa[j]=s.charAt(i);
}
return new String(sa);
}
}
六、关系和区别
1、collection与collections
collection是一个接口,是Set,List,Queue的接口
collections是一个类,容器的工具类
常用方法
2、ArrayList与HashSet
ArrayList有序,HashSet无序
List中可以重复,Set中不能重复
3、ArrayList与LinkedList
都可以重复
ArrayList插入数据慢,删除数据慢,但它是顺序结构,定位快
LinkedList插入、删除数据快,但它是链表结构,定位慢
4、线程安全的与线程不安全的
Vector与ArrayList区别
HashTable与HashMap区别
都是前者是线程安全的类。
来源:oschina
链接:https://my.oschina.net/u/4349408/blog/3294935