一.java集合
1.Java集合分为Collection和Map
2.Collection分为:List(Vector ArrayList LinkedList)、Set(HashSet LinkedSet TreeSet)
AarrayList
package collection;
import java.util.ArrayList;
public class Collection {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
//add:添加单个元素
arrayList.add("jack");
arrayList.add(10);
arrayList.add(true);
System.out.println("arrayList="+arrayList);
//remove删除元素
// arrayList.remove(0);//删除第一个元素
arrayList.remove("jack");//指定删除某个对象
System.out.println("arrayList="+arrayList);
//contains:查找元素是否存在
System.out.println(arrayList.contains("jack"));//false,因为删除了元素jack
//获取元素个数
System.out.println(arrayList.size());//2
//isEmpty:判断是否为空
System.out.println(arrayList.isEmpty());//false
//clear:清空
arrayList.clear();
System.out.println(arrayList);//[]
//addAll:添加多个元素
ArrayList arrayList2 =new ArrayList();
arrayList2.add("p");
arrayList2.add("l");
arrayList2.add("y");
arrayList.addAll(arrayList2);
System.out.println(arrayList);//[p, l, y]
//containsAll:查找多个元素
System.out.println(arrayList.containsAll(arrayList2));//true
//removeAll:删除多个元素
arrayList.add(19);
arrayList.removeAll(arrayList2);
System.out.println(arrayList);
}
}
1.1List接口方法
1.集合元素有序,可以重复
2.每个元素都有对应顺序的索引
3.List容器中的元素都对应一个整数型的序号记载其在容器的位置,可以根据序号存取容器中的元素
package collection;
import java.util.ArrayList;
public class List {
public static void main(String[] args) {
ArrayList List1 = new ArrayList();
List1.add("JACK");
List1.add("sparrow");
List1.add("Tom");
List1.add("Tom");
System.out.println("List1="+List1);//List1=[JACK, sparrow, Tom, Tom]
System.out.println(List1.get(0));//取出第一个元素,索引是从0开始的
}
}
操作集合元素的方法
package collection;
import java.util.ArrayList;
import java.util.List;
public class ListMethod {
public static void main(String[] args) {
List List1 = new ArrayList();
List1.add("q");
List1.add("w");
List1.add(1,"p");//在index=1,也就是q中插入"p",插入一个元素
System.out.println(List1);//[q, p, w]
ArrayList List2 = new ArrayList();
List2.add("S");
List2.add("a");
List1.addAll(1,List2);//在q中插入S,a,插入多个元素
System.out.println(List1);//[q, S, a, p, w]
System.out.println(List1.get(2));//获取指定位置元素,这里是第三个元素位置也就是a
System.out.println(List1.indexOf("a"));//2 a在集合中首次出现的位置
System.out.println(List1.lastIndexOf("w"));//4 w在集合中末次出现的位置
List1.remove(2);//删除一个元素值,在这里是删除了一个
System.out.println(List1);
List1.set(2,"e");//将第三个元素值替换成e
System.out.println(List1);
//List returnlist=List1.subList(1,3);//返回的是下标1和下标(3-1)也就是下标2
List1.subList(1,3);
// System.out.println("returnlist="+returnlist);
System.out.println(List1.subList(1,3));
}
}
1.2List三种遍历方式
1)方式一:使用iterator
Iterator iter = col.iterator();
while(iter.hasNext()){
Object o = iter.next();
}
2)方式二:使用增强for
for(Object o:col){
}
3)方式三:使用普通for
for(int i=0;i<list.size();i++){
Object object=list.get(i);
System.out.println(object);
}
Tips:
使用LinkedList完成 使用方式和ArrayList一样
package collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListFor {
public static void main(String[] args) {
List List = new ArrayList();
List.add("jack");
List.add("p");
List.add("y");
List.add(10);
//遍历
//1.迭代器
Iterator iterator = List.iterator();
while(iterator.hasNext()){
Object obj=iterator.next();
System.out.println(obj);
}
System.out.println("===========");
//2.增强for(用大写的I回车)
for (Object o :List) {
System.out.println("o="+o);
}
System.out.println("=============");
//3.普通for循环
for(int i=0;i<List.size();i++){
Object object = List.get(i);
System.out.println(object);
}
}
}
1.2.1 ArrayList
1.permits all elements,including null,ArrayList可以加入null,ArrayList可以加入null,并且有多个
2.ArrayList是由数组来实现数据存储的
3.ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码,在多线程情况下,不建议使用ArrayList
package collection;
import java.util.ArrayList;
@SuppressWarnings({"all"})
public class ArrayListDetail {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(null);
arrayList.add("jack");
arrayList.add(null);//可以放多个空值
System.out.println(arrayList);//[null, jack, null]
}
}
1.2.2 ArrayList底层结构和源码分析
1)ArrayList中维护了一个Object类型的数组elementData. transient Object[]elementData;
2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData容量为1.5倍
3)若使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍
1.3 Vector
1)Vector类的定义说明
public class Vector<E>
extends AbstractList<E>
implements List<E>,RandomAccess,Cloneable,Serializable
2)Vector底层也是一个对象数组,protected Object[] elenmentData;
3)Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized
public synchronized E get(int index){
if(index>=elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
4)在开发中,需要线程同步安全时,考虑使用Vector
1.3.1 Vector底层结构和源码分析
1.如果是无参,默认10,满后,就按2倍扩充,如果指定大小,则每次直接按2倍扩
package list;
import java.util.Vector;
public class Vector_{
public static void main(String[] args) {
//无参构造器
Vector vector= new Vector();
for(int i=0;i<10;i++){
vector.add(i);
}
//源码解读
//1.new Vector()底层
/*
public Vector(){
this(10);
}
//2.vector.add(i)
2.1 下面这个方法就添加数据到vector集合
public synchronized boolean add(E e){
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
2.2//确定是否需要扩容 条件:minCapacity - elementData.length > 0
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
2.3//如果需要的数组大小 不够用,就扩容,扩容的算法
//int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
// capacityIncrement : oldCapacity);
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
*/
}
}
1.4 LinkedList
1.LinkedList底层实现了双向链表和双端队列特点
2.可以添加任意元素(元素可以重复),包括null
3.线程不安全,没有实现同步
1.4.1 LinkedList底层结构
1.LinkedList底层维护了一个双向链表
2.LinkedList中维护了两个属性first和last分别指向 首节点和尾节点
3.每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表。
4.所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高
5.模拟一个简单的双向链表
package list;
public class LinkedList01 {
public static void main(String[] args) {
//模拟一个简单的双向链表
Node jack = new Node("jack");
Node Tom = new Node("Tom");
Node merry = new Node("merry");
//连接三个结点,形成双向链表
//jack->Tom->merry
jack.next =Tom;
Tom.next = merry;
//merry->Tom->jack
merry.pre = Tom;
Tom.pre = jack;
Node first = jack;//让first引用指向jack,就是双向链表的头
Node last = merry;//让last引用指向merry,双向链表的尾
}
}
//定义一个Node类,Node对象 表示双向链表的一个节点
class Node{
public Object item;//真正存放数据
public Node next;//指向后一个节点
public Node pre;//指向前一个节点
public Node(Object name){
this.item = name;
}
public String toString(){
return "Node name="+item;
}
}
2.1 Set接口和常用方法
1.Set接口基本介绍
1)无序,没有索引
2)不允许重复元素,所以最多包含一个null
2.Set接口常用方法
1)和List接口一样,也是Collection的子接口,因此,常用方法和Collection接口一样
3.Set接口遍历方法
1)可以使用迭代器
2)增强for
3)不能使用索引的方式来获取
package collection.set_;
import javafx.beans.binding.ListExpression;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetMethod {
public static void main(String[] args) {
//1. 以Set接口的实现类 HashSet
//2.set接口的实现类的对象(Set接口对象),不能存放重复元素,但可以有null
//3.set接口对象存放数据是无序
//4.注意:取出的顺序是一定的虽然不是添加的顺序,但是是固定的
Set set = new HashSet();
set.add("john");
set.add("lucy");
set.add("john");//重复
set.add("jack");
set.add(null);
set.add(null);//再次添加null
System.out.println(set);//[null, john, lucy, jack]
//遍历
//方式1:使用迭代器
Iterator iterator = set.iterator();
while(iterator.hasNext()){
Object obj=iterator.next();
System.out.println(obj);
}
//方式2:增强for
for (Object o :set) {
System.out.println("o="+o);
}
//set接口对象,不能通过索引来获取
}
}
2.1.1 HashSet
1.实现了Set接口
2.HashSet实际上是HashMap
3.可以存放null值
4.HashSet不保证元素是有序的,取决于hash后,在确定索引的结果
5.不能有重复元素或对象
package collection.set_;
import java.util.HashSet;
public class HashSet01 {
public static void main(String[] args) {
HashSet set = new HashSet();
//1.在执行add方法后,会返回一个Boolean值
//2.添加成功为true 失败为false
//3.可以通过remove指定删除对象
System.out.println(set.add("john"));
System.out.println(set.add("jack"));
System.out.println(set.add("merry"));
System.out.println(set.add("john"));//如果添加失败会返回一个false//false
set.remove("john");
System.out.println(set);
}
}
2.1.2 HashSet底层机制
1.HashSet底层是HashMap
2.添加一个元素时,先得到Hash的值,会转成->索引值
3.找到存储数据表table,看这个索引位置是否已经存放的有元素
4.如果没有,直接加入
5.如果有,调用equals比较,如果相同就放弃添加,如果不同就添加到最后
2.2 LinkedHashSet
1.LinkedHashSet是HashSet的子类
2.LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
3.LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
4.LinkedHashSet不允许添加重复元素
package collection.set_;
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetSource {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add(new String("AA"));
set.add(456);
set.add(new Coustomer("li",1001));
set.add(123);
System.out.println(set);
}
}
class Coustomer{
private String name;
private int id;
public Coustomer(String name,int id){
this.name=name;
this.id=id;
}
}
2.3 TreeSet
package collection.set_;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSet_ {
public static void main(String[] args) {
//1.当使用无参构造器,创建treeSet,仍然是无序的
//2.将添加的元素按照字符串大小排序
//3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
//并指定排序规则
// TreeSet treeSet = new TreeSet();
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//下面调用String的compareTo方法进行字符串大小比较
return ((String)o2).compareTo((String) o1);
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("y");
System.out.println(treeSet);//[y, tom, sp, jack]
}
}
3.1 Map接口
1.Map与Collection并列存在,用于保存映射关系的数据
2.Map中的key和Value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3.Map中的key不允许重复
4.value可以重复
5.key可以为null,value也可以为null,且有多个,key为null只能有一个
6.常用String类作为key
7.key和Value之间存在单向一对一的关系
package map;
import java.util.HashMap;
import java.util.Map;
public class Map_ {
public static void main(String[] args) {
Map map = new HashMap();
map.put("no1","zhang");
map.put("no2","han");
map.put("no1","peng");//用新的值替换zhang//结果为peng
System.out.println(map);//{no2=han, no1=peng}
}
}
3.2 Map常用方法(例子为HashMap):
1.put :添加
2.remove:根据删除键删除映射关系
3.get:根据键获取值
4.size:获取元素个数
5.isEmpty:判断个数是否为0
6.clear:清除
7.containsKey:查找键是否存在
package map;
import java.awt.print.Book;
import java.util.HashMap;
import java.util.Map;
public class MapMethod {
public static void main(String[] args) {
//常用方法
Map map = new HashMap();
map.put("邓超",new Book1 ("",100));
map.put("邓超","孙俪");//替换了,也就是说邓超这个时候对应孙俪了而不是一本书
map.put("王金","马蓉");
map.put("张哲","马蓉");
map.put("刘星","null");
map.put("null","刘亦菲");
map.put("陆星","徐妍");
map.put("peng","X");
System.out.println(map);//{邓超=孙俪, null=刘亦菲, 王金=马蓉, 张哲=马蓉, 陆星=徐妍, 刘星=null}
map.remove("邓超");//也可以写成"邓超","孙俪"
System.out.println(map);//{null=刘亦菲, 王金=马蓉, 张哲=马蓉, 陆星=徐妍, 刘星=null}
map.remove("null");
System.out.println(map);//{王金=马蓉, 张哲=马蓉, 陆星=徐妍, 刘星=null}
map.get("王金");
System.out.println(map.get("王金"));//获取王金对应的值:马蓉
System.out.println(map.size());//获取元素个数:4
System.out.println(map.isEmpty());//判断个数是否为0:false
// map.clear();
System.out.println(map);//{}
System.out.println(map.containsKey("peng"));//如果不进行clear,为true,若进行,为false
}
}
class Book1{
private String name;
private int num;
public Book1(String name,int num) {
this.name = name;
this.num = num;
}
}
3.2.1 遍历方法
public class MapMethod {
public static void main(String[] args) {
//常用方法
Map map = new HashMap();
map.put("邓超",new Book1 ("",100));
map.put("邓超","孙俪");//替换了,也就是说邓超这个时候对应孙俪了而不是一本书
map.put("王金","马蓉");
map.put("张哲","马蓉");
map.put("刘星","null");
map.put("null","刘亦菲");
map.put("陆星","徐妍");
map.put("peng","X");
//第一组先取出所有的Key,通过Key取出对应的Value
Set keyset = map.keySet();
//(1)增强for
System.out.println("======第一种方式======");
for (Object key: keyset) {
System.out.println(key+"-"+map.get(key));
}
//(2)迭代器
System.out.println("======第二种方式======");
Iterator iterator = keyset.iterator();
while(iterator.hasNext()){
Object key = iterator.next();
System.out.println(key+"-"+map.get(key));
}
//第二组:把所有的values取出
Collection values = map.values();
//可以使用所有的Collection使用的遍历方法
//(1)增强for
System.out.println("=====取出所有的value======");
for(Object value : values){
System.out.println(value);
}
//(2)迭代器
System.out.println("=====取出所有的value 迭代器====");
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()){
Object value = iterator2.next();
System.out.println(value);
}
//第三组:通过EntrySet来获取k-v
Set entrySet = map.entrySet();
//(1)增强for
for(Object entry : entrySet){
//将entry转换成Map.Entry
System.out.println(entry);
}
//(2)迭代器
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()){
Object entry = iterator3.next();
System.out.println(entry);
}
3.2.2 HashMap底层机制
1.底层维护了Node类型的数组table,默认为null
2.当创建对象时,将加载因子初始化为0.75
3.当添加key-val时。通过key的哈希值得到在table的索引,然后判断是否有元素,如果没有直接添加,如果有,继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换成val;如果不相等需要判断是树结构还是链表结构,如果发现容量不足,则需要扩容
4.第一次添加,扩容table量为16,临界值为12
5.以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,也就是24
3.3 Hashtable
1.基本介绍(例子中包含Hashtable扩容)
1)存放的元素是键值对:即K-V
2)hashtable的键和值都不能为null
3)hashTable使用方法基本上和HashMap一样
4)hashTable是线程安全的,hashMap是线程不安全的
package map;
import java.util.Hashtable;
public class HashTableExercise {
public static void main(String[] args) {
Hashtable table = new Hashtable();
table.put("john",100);
// table.put(null,100);//显示异常 NullException
// table.put("john",null);//显示异常 NullException
table.put("lucy",100);
table.put("lic",100);
table.put("lic",88);//替换了,将以88替换成100
System.out.println(table);
table.put("hello1",1);
table.put("hello2",1);
table.put("hello3",1);
table.put("hello4",1);
table.put("hello5",1);
table.put("hello6",1);
System.out.println(table);
//Hashtable的底层
//1.底层有数组 Hashtable$Entry[] 初始化大小为11
//2.临界值 threshod 8 = 11 * 0.75
//3.扩容:按照自己的想法扩容进行就可以
}
}
3.4 TreeMap
package map;
import java.util.Comparator;
import java.util.TreeMap;
public class TreeMap_ {
public static void main(String[] args) {
//使用默认构造器,创建TreeMap,是无序的
// TreeMap treeMap = new TreeMap();
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//按照传入的大小进行排序
return ((String)o2).compareTo((String)o1);//按照首字母顺序 t,s,k 从大到小
}
});
// treeMap.put("jack",new Book2( "A",100));
treeMap.put("tom","汤姆");
treeMap.put("kris","克瑞斯");
treeMap.put("smith","史密斯");
System.out.println(treeMap);
}
}
class Book2{
private String name;
int price;
public Book2(String name,int price){
this.name=name;
this.price=price;
}
}