Java集合、API、Collection接口及其子类方法、Collections类
1.集合概念
储存一个班的成员信息,假设一个班容纳30个人。
当我们需要保存这样一组元素的时候,我们需要使用一个容器,数组就是这样一个容器。
但是数组有缺点:数组一旦定义,长度就不能再变化。
在开发实践中,经常需要保存一些变长的数据集合,我们需要能够动态增长长度的容器来保存我们的数据。
而我们需要对数据的保存的逻辑可能各种各样,于是就有了各种各样的数据结构。Java中对于各种数据结构的实现,就是我们用到的集合。
2.集合API
Java的集合框架是由很多接口、抽象类、具体类组成的,位于java.util包
3.Collection接口
Collection接口 定义了存取一组对象的方法,其子接口Set和List分别定义了储存方式。
Set 中的数据对象无序且不重复。
List中的数据对象有序且重复
在Collection中定义了一些集合中共有方法:
boolean add(object element);
boolean remove(object element);
boolean clear();
int size();
boolean isEmpty();
boolean contains(object element);
boolean retainAll(Collection c);求交集,集合数据发生变化就返回true,不变返回false;
public class CollectionDemo {
public static void main(String[] args) {
//泛型通过泛型语法为集合设置一个类型,只能储存设置的数据类型
//集合是容器可以储存任何类型(只能是引用类型)
Collection<String> collection = new ArrayList<>();
collection.add("w");
collection.add("s");
collection.add("a");
collection.add("f");
Collection<String> collection1 = new ArrayList<>();
collection1.add("a");
collection1.add("j");
collection1.add("k");
collection1.add("l");
System.out.println(collection.contains("w")); //contains()是否包含 方法
System.out.println(collection.equals(collection1)); //equal() 比较内容是否相同方法
System.out.println(collection.isEmpty()); //判断是否为空
System.out.println(collection.remove("w"));//remove() 删除某个字符串
System.out.println(collection);
System.out.println(collection.size()); //求长度 数组中.length属性 字符串中 .length()方法 集合中 .size()方法
//System.out.println(collection.addAll(collection1)); //addAll() 将另一个集合全部添加进来
//collection1.clear(); //清除
System.out.println(collection.retainAll(collection1)); //求交集 如果有变化就是true 如果不变完全相同则为false
System.out.println(collection);
collection.toArray();
Object[] a = collection1.toArray(new String[collection1.size()]); //将集合转化为数组
System.out.println(Arrays.toString(a));
}
}
4.List接口及实现类
1)List继承了Collection接口,有三个实现类
ArrayList 数组列表,数据采用数组方式储存。
LinkedList 链表
Vector 数组列表,添加同步锁,线程安全的
2)ArrayList和LinkedList优点
ArrayList实现了长度可变的数组,在内存中分配连续的空间。
遍历元素和随机访问元素的效率比较高
LinkedList采用链表储存方式。
插入、删除元素时效率比较高
3)ArrayList的常用方法
add(int index,E element)
get(int index)
indexOf(object o)
lastIndexOf(object o)
remove(int index) 删除并返回指定位置元素
removeRange(int fromIndex,int toIndex) 删除指定区间的元素(子类继承使用)
set(int index,E element)
public class ArrayListDemo4 {
public static void main(String[] args) {
//去除重复元素
ArrayList<String> arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("c");
arrayList.add("c");
arrayList.add("d");
arrayList.add("e");
arrayList.add("c");
System.out.println(arrayList);
for(int i=0;i<arrayList.size();i++){
for(int j =i+1;j<arrayList.size();j++){
if(arrayList.get(i)==arrayList.get(j)){
arrayList.remove(j);
j--;
}
}
}
System.out.println(arrayList);
}
}
4)LinkedList的常用方法
add(int index,object element)
addFirst(object element)
addLast(ojbect element)
get(int index)
removeFirst()
removeLast()
remove(int index)
getFrist()
getLast()
public class LinkedListDemo1 {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("a"); //默认加到后面
linkedList.addFirst("b"); //将元素加到前面
linkedList.addLast("c"); //将元素加到后面
linkedList.add("d");
System.out.println(linkedList.get(2));
System.out.println(linkedList);
System.out.println(linkedList.getFirst());
System.out.println(linkedList.getLast());
linkedList.remove(3);
System.out.println(linkedList.removeFirst());
System.out.println(linkedList.removeLast());
}
}
5.List接口集合迭代
1)for循环遍历
public class ArrayList_one {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>();
al.add("No one");
al.add("No two");
al.add("No one");
for(int i=0;i<al.size();i++){
System.out.println(al.get(i));
}
}
}
2)增强for循环的遍历
public class HM1 {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
Scanner scanner = new Scanner(System.in);
Map<String, String> map = new HashMap<>();
map.put("1930","乌拉圭");
map.put("1934","意大利");
map.put("1938","意大利");
map.put("1950","乌拉圭");
map.put("1954","西德");
map.put("1958","巴西");
map.put("1962","巴西");
map.put("1966","英格兰");
map.put("1970","巴西");
map.put("1974","西德");
map.put("1978","阿根廷");
map.put("1982","意大利");
map.put("1986","阿根廷");
map.put("1990","西德");
map.put("1994","巴西");
map.put("1998","法国");
map.put("2002","巴西");
map.put("2006","意大利");
map.put("2010","西班牙");
map.put("2014","德国");
map.put("2018","法国");
//map.get(); 根据键输出值
System.out.println("输入一个年份获取该年夺得的世界杯,格式例如:2002");
String s = scanner.next();
if(map.containsKey(s)){
System.out.println("该年夺得世界杯的是:"+map.get(s));
}else{
System.out.println("这年没世界杯");
}
System.out.println("输入一个国家获得大力神杯的年份,格式例如:巴西");
String s1 = scanner.next();
if(map.containsValue(s1)){
System.out.println("该年夺得世界杯的是:");
for(String w:map.keySet()){
if(map.get(w).equals(s1)){
hs.add(w);
}
}
System.out.print(hs);
}else{
System.out.println("该国没得世界杯");
}
}
}
3)迭代器遍历(Iterator)
public class IteratirDemo {
public static void main(String[] args) {
ArrayList<String> al= new ArrayList<>();
al.add("b");
al.add("a");
al.add("c");
al.add("d");
al.add("d");
al.add("d");
al.add("d");
Iterator<String> it = al.iterator();
while(it.hasNext()){
String e = it.next();
if(e.equals("d")){
it.remove();
}
}
System.out.println(al);
ListIterator<String> it1= al.listIterator();
while(it1.hasPrevious()){
String e = it1.next();
if(e.equals("b")){
it1.remove();
}
}
System.out.println(al);
}
}
6.Set接口
-
Set接口继承了Collection接口。
Set中所有储存的元素是不重复的,但是是无序的,Set中的元素是没有索引的
1)HashSet
HashSet类中的元素不能重复,即彼此调用equals方法比较,都返回false
底层数据结构是哈希表+链表
哈希表依赖于哈希值储存
public class Car {
private int no;
private String name;
public Car(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return no == car.no &&
Objects.equals(name, car.name);
}
@Override
public int hashCode() {
return Objects.hash(no, name);
}
}
public class HashSetDemo2 {
public static void main(String[] args) {
Car car1 = new Car(1,"劳斯莱斯");
Car car2 = new Car(2,"法拉利");
Car car3 = new Car(3,"兰博基尼");
Car car4 = new Car(1,"劳斯莱斯");
HashSet<Car> hs = new HashSet<>();
hs.add(car1);
hs.add(car2);
hs.add(car3);
hs.add(car4);
System.out.println(hs);
}
}
//结果是:[Car{no=2, name='法拉利'}, Car{no=3, name='兰博基尼'}, Car{no=1, name='劳斯莱斯'}]
HashSet去重原理
<1>第一种HashSet的泛型是基本数据类型
int类型本身的数据符合HashCode
float类型是32位二进制组成只需要转成int类型
long类型由64位二进制组成,Hashcode的解决是将long类型的高32位与低32位进行异或运算取结果的低32位,最后转换为整形。
double 会先将二进制转成long类型的二进制,然后再将long类型转成int
Boolean类型 最简单 只有true和false两种 那么只规定两个数字作为HashCode就可以
String类型 计算哈希值是把字符串拆分成字符数组,然后分别去计算每个字符的值进行累加,最后返回。
<2>第二种自定义对象
去重原理解析:1.创建一个默认长度16的数组,数组名table
2.根据元素的哈希值跟数组的长度求余计算出应存入的位置(哈希算法)
3.判断当前位置是否为null,如果是null直接存入
4.如果位置不为null.表示有元素,则调用equals方法比较
5.如果一样,则不存,如果不一样,则存入数组。
自定义对象需要重写系统的hashCode方法和equals方法
如果重写了系统的hashCode方法和equals方法,那么就只允许添加第一个对象,相同的第二个对象是不会添加的,这是因为 通过 对象属性计算的hash值 ,因为对象里面的属性都一直,那么 hash值是一致的,euqals判断也一致,所以就不会进行添加。
2)TreeSet
可以给Set集合中的元素进行指定方式的排序。储存的对象必须实现comparable接口。
TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)
public class TreeSetDemo {
public static void main(String[] args) {
Car car1 = new Car(3,"大众3",300000);
Car car2 = new Car(2,"大众2",350000);
Car car3 = new Car(1,"大众1",3400000);
Car car4 = new Car(1,"大众1",3400000);
TreeSet<Car> ts = new TreeSet<>();
ts.add(car2);
ts.add(car3);
ts.add(car1);
ts.add(car4);
System.out.println(ts);//[Car{no=1, name='大众1', price=3400000}, Car{no=2, name='大众2', price=350000}, Car{no=3, name='大众3', price=300000}]
}
}
7.Set接口集合迭代
遍布方式有两种
1)增强for循环
2)迭代器遍历
8.Map接口
1)Map接口概述
将键映射到值的对象
一个映射不能包含重复的键
每个键最多只能映射到一个值
2)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)
Collection values()
Set keySet()
Set<Map.Entry<K,V>> entrySet()
3)HashMap
HashMap中元素的key值不能重复,排序顺序是不固定的,可以储存一个为null的键。
4)TreeMap
TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该使用TreeMap,key值所有类必须实现Comparable接口。
适用于按自然顺序或自定义顺序遍历键(key)
TreeMap根据key值排序,key值需要实现comparable接口,重写compareto方法。TreeMap根据compareto的逻辑,对key进行排序。
键是红黑树结构,可以保证键的排序和唯一性
5)HashTable
实现了同步。
不能储存为null的键。
6)Map集合遍历
方式1:根据键找值
- 获取所有键的集合
- 遍历键的集合,获取到每一个键
- 根据键找值
方式2:根据键值对对象找键和值
- 获取所有键值对对象的集合
- 遍历键值对对象的集合,获取到每一个键值对对象
- 根据键值对对象找键和值
public class HashMapDemo2 {
public static void main(String[] args) {
HashMap<String,String> hm = new HashMap<>();
hm.put("q","qqq");
hm.put("w","www");
hm.put("e","eee");
//哈希图遍历 Map.Entry<> entrySet();
Set<Map.Entry<String,String>> entry = hm.entrySet();
for(Map.Entry<String,String> ment: entry){
System.out.println(ment.getKey()+"="+ment.getValue());
}
Set<String> hs = hm.keySet();
for(String h :hs){
String value = hm.get(h);
System.out.println(h+"="+value);
}
}
}
9.Collections类
Collections是集合类的工具类,于数组的工具类Arrays类似
addAll(Col lection<? super T> c, T… elements);
binarySearch(List<? extends Comparable<? super T>> l ist, T key)
sort(List list)
sort(List list, Comparator<? super T> c)
swap(List<?> list, int i, int j)
copy(List<? super T> dest, List<? extends T> src) ; 注意 dest size需大于等于src.size
emptyList() 返回为空的集合,不能添加数据
fill(List<? super T> l ist, T obj)
max(Col lection<? extends T> col l)
min(Col lection<? extends T> col l)
replaceAll(List list, T oldVal, T newVal)
reverse(List<?> list)
shuffle(List<?> list) 随机排序
copy(dest,src)集合复制
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
al.add(1);
al.add(4);
al.add(3);
al.add(5);
//排序sort();
List<Integer> list = new ArrayList<>();
list.add(6);
list.add(7);
list.add(8);
Collections.copy(al,list);
Collections.sort(al);
System.out.println(al);
//binarySearch 二分查找先排序
System.out.println(Collections.binarySearch(al,3));
System.out.println(Collections.max(al));
System.out.println(Collections.min(al));
System.out.println(al);
System.out.println(list);
Collections.fill(al,1);
System.out.println(al);
Collections.shuffle(list);
System.out.println(list);
Collections.swap(list,2,1);
System.out.println(list);
}
}