文章目录
为什么要学集合?
当我们要存储一组类型相同的元素时候,我们应该用一个容器来存储,数组就是这样一个容器
那数组有什么缺点么?
数组一旦定义,长度就不能再变化
然而当我们在开发的实践中,经常需要保存一些变长的数据集合,于是,我们需要一些能够动态增长长度的容器来保存我们的数据.
而我们需要对数据的保存的逻辑可能各种各样,于是就有了各种各样的数据结构,Java中对于各种数据结构的实现,就是我们用到的集合.
集合体系概述
Java的集合框架是由很多接口,抽象类,具体类组成的,都在java.util包中.
Collection接口
collection接口定义了存取一组对象的方法,其子接口set和list分别定义了存储方式
--set 中的数据对象没有顺序且不可以重复
--list 中的数据对象有顺序且可以 重复
Collention中的方法
boolean add(Object element); 添加一个元素
boolean addAll(Collection c); 添加一个集合到调用集合的后边
boolean remove(Object elemeny); 删除集合指定的第一个元素
boolean removeAll(Collection c); 删除集合全部元素
void clear(); 清空
int size(); 集合长度
boolean isEmpty(); 集合是否为空
boolean contains(Object element); 子集
boolean containsAll(Collection c); 真子集
boolean retainAll(Collection c); 求交集
List接口及实现类
List继承了Collection接口,有三个实现的类
ArrayList
数组列表,数据采用数组方式存储。
LinkedList
链表
Vector
数组列表,添加同步锁,线程安全的
ArrayList
ArrayList实现了长度可变的数组,在内存中分配连续的空间。
遍历元素和随机访问元素的效率比较高
这里博主不是写的很全面,大概写了一下
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add("a");
al.add("d");
al.add("g");
al.add("b");
al.add("c");
al.add("s");
al.add("z");
//指定元素添加元素
al.add(0,"t");
//排序 要调用排序,那么就得实现Comparator接口,重写conpareTo方法
al.sort(new ArrayListDemo2());
System.out.println(al);
//删除
al.remove(5);
System.out.println(al);
}
}
public class ArrayListDemo1 extends ArrayList {
public static void main(String[] args) {
ArrayListDemo1 al = new ArrayListDemo1();
al.add("a");
al.add("d");
al.add("g");
al.add("b");
al.add("c");
al.add("s");
al.add("z");
//排序
al.sort(new ArrayListDemo2());
System.out.println(al);
//删除指定区间元素
al.removeRange(0,5);
System.out.println(al);
}
}
public class ArrayListDemo2 implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
}
上述代码运行结果
sort: [a, b, c, d, g, s, t, z]
removeIndex - 5: [a, b, c, d, g, t, z]
LinkedList
LinkedList采用链表存储方式。插入、删除元素时效率比较高
LinkedList list1 = new LinkedList();
for (int i = 1; i < 16; i++) {
list.add(i);
}
System.out.println(list1);
list1.add(0,0);
System.out.println(list1);
list1.addFirst("Yinyongleixing");
System.out.println(list1);
list1.addLast("还是引用类型");
System.out.println(list1);
System.out.println(list1.removeFirst());
System.out.println(list1.removeLast());
System.out.println(list1);
System.out.println(list1.remove(0));
System.out.println(list1);
System.out.println(list1.getFirst());
System.out.println(list1.getLast());
上述代码运行结果
list1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
list1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
list1: [Yinyongleixing, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
list1: [Yinyongleixing, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 还是引用类型]
Yinyongleixing
removeLast: 还是引用类型
list1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
list1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
getFirst: 0
getLast: 15
Vector
主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
public class VectorDemo {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add("a");
al.add("b");
al.add("c");
al.add("c");
al.add("d");
System.out.println("size: " + al.size());
System.out.println("remove: " + al.remove("a"));
System.out.println("getindex a : " + al.indexOf("a"));
}
}
上述代码运行结果
size: 5
remove: true
getindex a : 1
List接口迭代
ArrayList al = new ArrayList();
for循环遍历
通过索引值获取所对应的数据信息
for (int i = 0; i < al.size(); i++) {
for (int j = 1; j < al.size()-1; j++) {
if (al.get(i).equals(al.get(j))){
al.remove(i);
}
}
}
增强for循环遍历
也是通过迭代器的方法获取信息
for (Object obj: al) {
if (obj.equals("a")){
al.remove(obj);
break;
}
}
System.out.println(al);
迭代器遍历(Itertor)
通过集合返回迭代器。
这里要使用到hasnext() 方法
Iterator it = al.iterator();
while (it.hasNext()){
Object obj = it.next();
it.remove();
}
System.out.println(al);
上述代码运行结果
[a, d]
[d]
[]
Set接口
Set接口继承了Collection接口。
Set中所存储的元素是**不重复**的,但是**是无序**的, Set中的元素是**没有索引**的
HashSet
HashSet类中的元素不能重复,即彼此调用equals方法比较,都返回false。
底层数据结构是哈希表+链表
哈希表依赖于哈希值存储
向HashSet中添加元素时是如何判定重复元素?
底层是双保险的:既要提高判断效率,还要安全可靠
首先会获得添加内容hash值,判断hash值在集合中是否存在
但是内容不同时,hash值可能会相同,那么就不可靠
在hash值相同时,会调用equals方法,比较内容是否相同
public class Student implements Comparable<Student> {
private int num;
private String name;
private int age;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(int num, String name, int age) {
this.num = num;
this.name = name;
this.age = age;
}
/*
当hash值出现重复时,会调用eauals方法,进行内容判断
效率第,安全
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return num == student.num &&
age == student.age &&
Objects.equals(name, student.name);
}
/*
重写Object类中的hashCode(),来自己操作对象中包含的内容计算hash值
效率高,会出现重复
*/
@Override
public int hashCode() {
return Objects.hash(num, name, age);
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
", age=" + age +
'}';
}
//以学号排序
@Override
public int compareTo(Student o) {
return this.num-o.num;
}
}
public static void main(String[] args) {
//HashSet无序 不按照输入顺序 有自己特定的方法
//public native int hashCode(); 会调用此方法
HashSet<String> hs = new HashSet<>();
hs.add("a");
hs.add("a");
hs.add("b");
hs.add("仲裁");
hs.add("国有");
System.out.println(hs);
HashSet<Student> h = new HashSet<>();
Student s1 = new Student(101,"tom",20);
Student s2 = new Student(101,"tom",20);
Student s3 = new Student(102,"jim",20);
Student s4 = new Student(103,"bom",19);
h.add(s1);
h.add(s2);
h.add(s3);
h.add(s4);
System.out.println(h);
}
以上代码运行结果
[a, b, 仲裁, 国有]
[Student{num=102, name='jim', age=20}, Student{num=103, name='bom', age=19}, Student{num=101, name='tom', age=20}]
TreeSet
可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。
TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)
public static void main(String[] args) {
TreeSet<String> ts = new TreeSet();
ts.add("z");
ts.add("b");
ts.add("a");
ts.add("c");
ts.add("b");
ts.add("f");
System.out.println(ts);
TreeSet<Student> tst = new TreeSet<>();
Student s1= new Student(101,"jim",18);
Student s2= new Student(100,"tom",19);
Student s3= new Student(109,"bom",101);
Student s4 = new Student(001,"dom",1);
tst.add(s1);
tst.add(s2);
tst.add(s3);
tst.add(s4);
//年龄排序
System.out.println(tst);
}
以上代码运行结果
[a, b, c, f, z]
[Student{num=1, name='dom', age=1}, Student{num=100, name='tom', age=19}, Student{num=101, name='jim', age=18}, Student{num=109, name='bom', age=101}]
Map接口
Map接口中常用方法
V put(K key,V value)
V remove(Object key)
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
int size()
V get(Object key)
Set<K> keySet()
Collection<V> values()
Set<Map.Entry<K,V>> entrySet()
Map遍历
方式一:根据键找值
获取所有键的集合
遍历键的集合,获取到每一个键
根据键找值
map.keySet();
map.get();
Map<Integer,String> hm = new LinkedHashMap<>();
Set<Integer> s = hm.keySet();
for(Integer i:s){
System.out.println(i + "=" + hm.get(i) + ";");
}
方式二:根据键值对对象找键和值
获取所有键值对对象的集合
遍历键值对对象的集合,获取到每一个键值对对象
根据键值对对象找键和值
Set<Map.Entry<Integer,String>> set = hm.entrySet();
for (Map.Entry<Integer,String> entry:set) {
System.out.print(entry.getKey() + " == " + entry.getValue() + "; ");
}
TreeMap
TreeMap中所有的元素都保持着某种固定的顺序,
如果需要得到一个有序的Map就应该使用TreeMap,key值所在类必须实现Comparable接口。
适用于按自然顺序或自定义顺序遍历键(key)。
TreeMap根据key值排序,key值需要实现Comparable接口,
重写compareTo方法。TreeMap根据compareTo的逻辑,对
key进行排序。
键是红黑树结构,可以保证键的排序和唯一性
HashMap
HashMap中元素的key值不能重复,即彼此调用equals方法,返回为false。排列顺序是不固定的。
HashTable
实现了同步
HashMap<Integer,String> map = new HashMap<Integer, String>();
//添加键值对
map.put(1,"张三");
map.put(2,"李四");
map.put(3,"王五");
map.put(4,"赵六");
System.out.println(map);
//都是引用类型
HashMap<String,String> hashMap = new HashMap<String, String>();
hashMap.put("姓名","张三");
hashMap.put("年龄","18");
hashMap.put("籍贯","陕西省");
System.out.println(hashMap);
// V remove(Object key) 删除
hashMap.remove("姓名");
System.out.println(hashMap);
System.out.println(hashMap.get("籍贯"));
System.out.println(hashMap.containsKey("年龄"));
System.out.println(hashMap.containsValue("山西省"));
System.out.println(hashMap.containsValue("陕西省"));
System.out.println(hashMap.size());
System.out.println(hashMap.isEmpty());
System.out.println(hashMap);
hashMap.clear();
System.out.println(hashMap);
以上代码运行结果
{1=张三, 2=李四, 3=王五, 4=赵六}
{姓名=张三, 年龄=18, 籍贯=陕西省}
{年龄=18, 籍贯=陕西省}
陕西省
true
false
true
2
false
{年龄=18, 籍贯=陕西省}
{}
Process finished with exit code 0